{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Lymah","description":"The latest articles on DEV Community by Lymah (@lymah).","link":"https:\/\/dev.to\/lymah","image":{"url":"https:\/\/media2.dev.to\/dynamic\/image\/width=90,height=90,fit=cover,gravity=auto,format=auto\/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1170961%2F98ca50d4-d70c-4fc3-a3fb-e4b6e74c149c.jpg","title":"DEV Community: Lymah","link":"https:\/\/dev.to\/lymah"},"language":"en","item":[{"title":"From Localhost to Production: Deploying an AI Blog Generator (FastAPI + React)","pubDate":"Sun, 25 Jan 2026 18:39:41 +0000","link":"https:\/\/dev.to\/lymah\/from-localhost-to-production-deploying-an-ai-blog-generator-fastapi-react-4m1n","guid":"https:\/\/dev.to\/lymah\/from-localhost-to-production-deploying-an-ai-blog-generator-fastapi-react-4m1n","description":"<p><em>Part 2 of building an AI blog generator with FastAPI, React, Hugging Face, Railway, and Vercel.<\/em><\/p>\n\n<blockquote>\n<p>This post is for developers who\u2019ve built full-stack apps locally and want to confidently ship them to production without overengineering.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6tmmo44b5bq8t56wcxg.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6tmmo44b5bq8t56wcxg.png\" alt=\"Deployment success\" width=\"800\" height=\"450\"><\/a><\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo96jwlun9uf4zg17s21j.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo96jwlun9uf4zg17s21j.png\" alt=\"frontent-vercel\" width=\"800\" height=\"405\"><\/a><\/p>\n\n\n\n\n<h3>\n  \n  \n  Welcome Back!\n<\/h3>\n\n<p>In <a href=\"https:\/\/dev.to\/lymah\/building-an-ai-blog-generator-with-fastapi-react-and-hugging-face-49m5\">Part 1<\/a>, I built an AI-powered blog generator locally.<br>\nIn this post, I\u2019ll show how I deployed the full system to production using Railway and Vercel\u2014covering backend deployment, database setup, frontend integration, and the real issues I ran into along the way.<\/p>\n\n<p>In this post, I'll walk you through:<\/p>\n\n<ul>\n<li>Deploying the FastAPI backend to Railway<\/li>\n<li>Setting up PostgreSQL in production<\/li>\n<li>Deploying the React frontend to Vercel<\/li>\n<li>Connecting everything together<\/li>\n<li>The challenges I faced and how I solved them<\/li>\n<\/ul>\n\n<ol>\n<li><a href=\"https:\/\/frontend-2t151l0f1-lymahs-projects.vercel.app\/\" rel=\"noopener noreferrer\">Live Demo<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Lymah123\/ai-blog-generator?tab=readme-ov-file\" rel=\"noopener noreferrer\">GitHub<\/a><\/li>\n<\/ol>\n<h2>\n  \n  \n  Let's dive in! \n<\/h2>\n<h2>\n  \n  \n  Deployment Strategy\n<\/h2>\n\n<p>Before jumping into deployment, I needed to make some key decisions.<\/p>\n<h3>\n  \n  \n  Why Railway for Backend?\n<\/h3>\n\n<p>I chose <strong>Railway<\/strong> over alternatives like Heroku, AWS, or DigitalOcean because:<\/p>\n\n<ol>\n<li>\n<strong>PostgreSQL Integration<\/strong> - One-click database setup<\/li>\n<li>\n<strong>GitHub Integration<\/strong> - Automatic deployments on push<\/li>\n<li>\n<strong>Developer Experience<\/strong> - Clean UI, clear logs, easy configuration<\/li>\n<li>\n<strong>Pricing<\/strong> - $5\/month hobby plan is perfect for side projects<\/li>\n<li>\n<strong>Zero Config<\/strong> - Railway auto-detects Python and handles everything<\/li>\n<\/ol>\n<h3>\n  \n  \n  Why Vercel for Frontend?\n<\/h3>\n\n<p><strong>Vercel<\/strong> was the obvious choice for the React frontend:<\/p>\n\n<ol>\n<li>\n<strong>Built for React\/Vite<\/strong> - Optimized for frontend frameworks<\/li>\n<li>\n<strong>Global CDN<\/strong> - Lightning-fast content delivery<\/li>\n<li>\n<strong>Automatic HTTPS<\/strong> - SSL certificates out of the box<\/li>\n<li>\n<strong>Preview Deployments<\/strong> - Every PR gets its own URL<\/li>\n<li>\n<strong>Free Tier<\/strong> - Perfect for personal projects<\/li>\n<\/ol>\n<h3>\n  \n  \n  Architecture Overview\n<\/h3>\n\n<p>Here's what we're building:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     HTTPS      \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502             \u2502\u25c4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba\u2502             \u2502\n\u2502   Vercel    \u2502                 \u2502   Railway   \u2502\n\u2502  (Frontend) \u2502                 \u2502  (Backend)  \u2502\n\u2502             \u2502                 \u2502             \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                       \u2502\n                                       \u2502\n                                \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                                \u2502 PostgreSQL  \u2502\n                                \u2502  Database   \u2502\n                                \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Simple, scalable, and cost-effective.<\/p>\n\n\n\n\n<h2>\n  \n  \n  Part 1: Deploying Backend to Railway\n<\/h2>\n\n<h3>\n  \n  \n  Step 1: Preparing the Backend\n<\/h3>\n\n<p>Before deployment, I needed to ensure the backend was production-ready.<\/p>\n\n<h4>\n  \n  \n  Creating railway.json\n<\/h4>\n\n<p>Railway uses this file to understand how to deploy our app:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"$schema\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"https:\/\/railway.app\/railway.schema.json\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"build\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"builder\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"NIXPACKS\"<\/span><span class=\"w\">\n  <\/span><span class=\"p\">},<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"deploy\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"startCommand\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"uvicorn app.main:app --host 0.0.0.0 --port $PORT\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"restartPolicyType\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"ON_FAILURE\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"restartPolicyMaxRetries\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">10<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Key points:<\/strong><\/p>\n\n<ul>\n<li>\n<code>NIXPACKS<\/code> auto-detects Python and installs dependencies<\/li>\n<li>\n<code>--host 0.0.0.0<\/code> allows external connections<\/li>\n<li>\n<code>$PORT<\/code> uses Railway's dynamic port assignment<\/li>\n<li>Restart policy handles crashes gracefully<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Updating Production Dependencies\n<\/h4>\n\n<p>Made sure <code>requirements.txt<\/code> included production essentials:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>fastapi==0.104.1\nuvicorn[standard]==0.24.0\nsqlalchemy==2.0.23\npsycopg2-binary==2.9.9  # PostgreSQL driver\npydantic==2.5.0\npydantic-settings==2.1.0\npython-dotenv==1.0.0\nrequests==2.31.0\ngunicorn==21.2.0  # Production server\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Step 2: Setting Up Railway\n<\/h3>\n\n<h4>\n  \n  \n  Creating the Project\n<\/h4>\n\n<p>The process was surprisingly smooth:<\/p>\n\n<ol>\n<li>Went to <a href=\"https:\/\/railway.app\" rel=\"noopener noreferrer\">railway.app<\/a>\n<\/li>\n<li>Clicked \"Start a New Project\"<\/li>\n<li>Selected \"Deploy from GitHub repo\"<\/li>\n<li>Chose my <code>ai-blog-generator<\/code> repository<\/li>\n<li>\n<strong>Important:<\/strong> Selected <code>backend<\/code> as the root directory<\/li>\n<\/ol>\n\n<p>Railway immediately started building!<\/p>\n\n<h4>\n  \n  \n  Adding PostgreSQL\n<\/h4>\n\n<p>This was the easiest database setup I've ever done:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Click \"New\" \u2192 \"Database\" \u2192 \"PostgreSQL\"\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Railway automatically:<\/p>\n\n<ul>\n<li>Provisioned a PostgreSQL instance<\/li>\n<li>Created the <code>DATABASE_URL<\/code> environment variable<\/li>\n<li>Connected it to my backend service<\/li>\n<\/ul>\n\n<p><strong>No configuration files, no manual connection strings - just magic.<\/strong> <\/p>\n\n<h3>\n  \n  \n  Step 3: Environment Variables\n<\/h3>\n\n<p>Railway makes environment management clean and secure.<\/p>\n\n<p>I added these variables via the Railway dashboard:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>HUGGINGFACE_API_KEY=hf_xxxxxxxxxxxxx\nHUGGINGFACE_MODEL=meta-llama\/Llama-3.3-70B-Instruct\nENVIRONMENT=production\nAPP_NAME=AI Blog Generator API\nVERSION=1.0.0\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Pro tip:<\/strong> The <code>DATABASE_URL<\/code> was automatically set when I added PostgreSQL. No manual configuration needed!<\/p>\n\n<h3>\n  \n  \n  Step 4: First Deployment Attempt\n<\/h3>\n\n<p>I pushed my code and watched the build logs:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>git add <span class=\"nb\">.<\/span>\ngit commit <span class=\"nt\">-m<\/span> <span class=\"s2\">\"Prepare for Railway deployment\"<\/span>\ngit push origin main\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Railway detected the push and started building...<\/p>\n\n<p><strong>And it failed.<\/strong> \ud83d\ude05<\/p>\n\n<h3>\n  \n  \n  Challenge #1: Import Errors\n<\/h3>\n\n<p><strong>The Problem:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>ModuleNotFoundError: No module named 'app.database'\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>The Cause:<\/strong><\/p>\n\n<p>My local environment had different import paths than production.<\/p>\n\n<p><strong>The Solution:<\/strong><\/p>\n\n<p>I realized I needed to ensure all imports were relative to the <code>backend<\/code> directory. Updated <code>app\/main.py<\/code>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Before (worked locally)\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">database<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">engine<\/span><span class=\"p\">,<\/span> <span class=\"n\">Base<\/span>\n\n<span class=\"c1\"># After (works everywhere)\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">app.database<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">engine<\/span><span class=\"p\">,<\/span> <span class=\"n\">Base<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Lesson learned:<\/strong> Always test imports from the project root!<\/p>\n\n<h3>\n  \n  \n  Challenge #2: Database Tables Not Created\n<\/h3>\n\n<p><strong>The Problem:<\/strong><\/p>\n\n<p>API worked, but generating blogs failed with:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>relation \"blog_posts\" does not exist\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>The Cause:<\/strong><\/p>\n\n<p>FastAPI wasn't creating tables on startup in production.<\/p>\n\n<p><strong>The Solution:<\/strong><\/p>\n\n<p>Updated the lifespan context manager in <code>main.py<\/code>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">contextlib<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">asynccontextmanager<\/span>\n\n<span class=\"nd\">@asynccontextmanager<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">lifespan<\/span><span class=\"p\">(<\/span><span class=\"n\">app<\/span><span class=\"p\">:<\/span> <span class=\"n\">FastAPI<\/span><span class=\"p\">):<\/span>\n    <span class=\"c1\"># Startup: Create tables\n<\/span>    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Creating database tables...<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">Base<\/span><span class=\"p\">.<\/span><span class=\"n\">metadata<\/span><span class=\"p\">.<\/span><span class=\"nf\">create_all<\/span><span class=\"p\">(<\/span><span class=\"n\">bind<\/span><span class=\"o\">=<\/span><span class=\"n\">engine<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Tables created successfully!<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">yield<\/span>\n    <span class=\"c1\"># Shutdown\n<\/span>    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Application shutting down<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">app<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">FastAPI<\/span><span class=\"p\">(<\/span><span class=\"n\">lifespan<\/span><span class=\"o\">=<\/span><span class=\"n\">lifespan<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Now tables are created automatically on every deployment!<\/p>\n\n<h3>\n  \n  \n  Step 5: Generating a Domain\n<\/h3>\n\n<p>Railway provides a free subdomain:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Settings \u2192 Networking \u2192 Generate Domain\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Got: <code>https:\/\/ai-blog-generator-production-bd0c.up.railway.app<\/code><\/p>\n\n<p>Tested it:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>curl curl https:\/\/ai-blog-generator-production-bd0c.up.railway.app\/health\n\n<span class=\"c\"># Response:<\/span>\n<span class=\"o\">{<\/span><span class=\"s2\">\"status\"<\/span>:<span class=\"s2\">\"healthy\"<\/span>,<span class=\"s2\">\"environment\"<\/span>:<span class=\"s2\">\"production\"<\/span><span class=\"o\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Backend deployed successfully!<\/strong> <\/p>\n\n<h2>\n  \n  \n  <img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop1e63qlmo7usqskd0js.png\" alt=\"backend deployment logs\" width=\"800\" height=\"370\">\n<\/h2>\n\n<h2>\n  \n  \n  Part 2: Deploying Frontend to Vercel\n<\/h2>\n\n<h3>\n  \n  \n  Step 1: Preparing the Frontend\n<\/h3>\n\n<h4>\n  \n  \n  Environment Configuration\n<\/h4>\n\n<p>Created <code>.env.production<\/code>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>VITE_API_URL=https:\/https:\/\/ai-blog-generator-production-bd0c.up.railway.app\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This tells the frontend where to find the backend in production.<\/p>\n\n<h4>\n  \n  \n  Vercel Configuration\n<\/h4>\n\n<p>Created <code>vercel.json<\/code> for optimal deployment:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"buildCommand\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"npm run build\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"outputDirectory\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"dist\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"framework\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"vite\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"rewrites\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"w\">\n    <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"source\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"\/(.*)\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"destination\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"\/index.html\"<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">]<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The <code>rewrites<\/code> section ensures React Router works properly in production.<\/p>\n\n<h3>\n  \n  \n  Step 2: Deploying to Vercel\n<\/h3>\n\n<h4>\n  \n  \n  Import from GitHub\n<\/h4>\n\n<ol>\n<li>Logged into <a href=\"https:\/\/vercel.com\" rel=\"noopener noreferrer\">vercel.com<\/a>\n<\/li>\n<li>Clicked \"New Project\"<\/li>\n<li>Selected my repository<\/li>\n<li>\n<strong>Critical:<\/strong> Set root directory to <code>frontend<\/code>\n<\/li>\n<\/ol>\n\n<h4>\n  \n  \n  Build Configuration\n<\/h4>\n\n<p>Vercel auto-detected everything:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Framework: Vite\nBuild Command: npm run build\nOutput Directory: dist\nInstall Command: npm install\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Adding Environment Variable\n<\/h4>\n\n<p>Added the most important variable:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>VITE_API_URL = https:\/\/ai-blog-generator-production-bd0c.up.railway.app\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Clicked \"Deploy\" and waited...<\/p>\n\n<p><strong>First deployment: Success!<\/strong> <\/p>\n\n<p>Got URL: <code>https:\/\/frontend-ochre-rho-71.vercel.app\/<\/code><\/p>\n\n<h3>\n  \n  \n  Challenge #3: CORS Errors\n<\/h3>\n\n<p>Opened my Vercel URL and... nothing worked. <\/p>\n\n<p><strong>The browser console showed:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Access to fetch at 'https:\/\/ai-blog-generator-production-bd0c.up.railway.app\/api\/v1\/generate' \nfrom origin 'https:\/\/frontend-ochre-rho-71.vercel.app' has been blocked by CORS policy\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>The Problem:<\/strong><\/p>\n\n<p>The backend wasn't configured to accept requests from the Vercel domain.<\/p>\n\n<p><strong>The Solution:<\/strong><\/p>\n\n<p>Added <code>CORS_ORIGINS<\/code> to Railway:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>CORS_ORIGINS=https:\/\/frontend-ochre-rho-71.vercel.app\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Railway auto-redeployed the backend with new CORS settings.<\/p>\n\n<p><strong>Hard refreshed the frontend (Ctrl+Shift+R) and...<\/strong><br>\n<strong>Connected!<\/strong> The status indicator turned green!<\/p>\n<h2>\n  \n  \n  <img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4dwq941o285fzxjdiyrk.png\" alt=\"frontend deployment dashboard\" width=\"800\" height=\"337\">\n<\/h2>\n<h2>\n  \n  \n  Testing in Production\n<\/h2>\n<h3>\n  \n  \n  First Blog Generation\n<\/h3>\n\n<p>Held my breath and tried generating a blog:<\/p>\n\n<p><strong>Input:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Topic: The Future of Cloud Computing\nTone: Professional\nLength: Medium\nKeywords: cloud, scalability, innovation\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Clicked \"Generate Blog Post\"...<\/strong><\/p>\n\n<p>20 seconds later...<\/p>\n\n<p><strong>Success!<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Title: The Future of Cloud Computing: Embracing Innovation and Scalability\n\nWord Count: 1,247 words\nSEO Score: 82\n\n[Full formatted blog content displayed]\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Everything worked:<\/p>\n\n<ul>\n<li>\u2705 AI generation<\/li>\n<li>\u2705 Database storage<\/li>\n<li>\u2705 SEO scoring<\/li>\n<li>\u2705 Copy to clipboard<\/li>\n<li>\u2705 Download as Markdown<\/li>\n<li>\u2705 Blog history<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Performance Testing\n<\/h3>\n\n<p>I generated several blogs to test:<\/p>\n\n<p><strong>Response Times:<\/strong><\/p>\n\n<ul>\n<li>API health check: ~50ms<\/li>\n<li>Blog generation: 25-35 seconds (AI processing)<\/li>\n<li>Blog retrieval: ~100ms<\/li>\n<li>Blog list: ~150ms<\/li>\n<\/ul>\n\n<p><strong>Database:<\/strong><\/p>\n\n<ul>\n<li>Tables created automatically \u2705<\/li>\n<li>Blogs saving correctly \u2705<\/li>\n<li>Queries performing well \u2705<\/li>\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Challenges &amp; Solutions Summary\n<\/h2>\n\n<p>Let me share all the issues I encountered and how I solved them:<\/p>\n\n<h3>\n  \n  \n  1. Module Import Errors\n<\/h3>\n\n<p><strong>Error:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"nb\">ModuleNotFoundError<\/span><span class=\"p\">:<\/span> <span class=\"n\">No<\/span> <span class=\"n\">module<\/span> <span class=\"n\">named<\/span> <span class=\"sh\">'<\/span><span class=\"s\">app.database<\/span><span class=\"sh\">'<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Solution:<\/strong><br>\nEnsured all imports were absolute from the project root:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">app.database<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">engine<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">app.models.blog<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">BlogPost<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">app.services.ai_service<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">hf_service<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  2. Database Tables Not Created\n<\/h3>\n\n<p><strong>Error:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>psycopg2.errors.UndefinedTable: relation \"blog_posts\" does not exist\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Solution:<\/strong><br>\nAdded lifespan context manager to create tables on startup:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"nd\">@asynccontextmanager<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">lifespan<\/span><span class=\"p\">(<\/span><span class=\"n\">app<\/span><span class=\"p\">:<\/span> <span class=\"n\">FastAPI<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">Base<\/span><span class=\"p\">.<\/span><span class=\"n\">metadata<\/span><span class=\"p\">.<\/span><span class=\"nf\">create_all<\/span><span class=\"p\">(<\/span><span class=\"n\">bind<\/span><span class=\"o\">=<\/span><span class=\"n\">engine<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">yield<\/span>\n\n<span class=\"n\">app<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">FastAPI<\/span><span class=\"p\">(<\/span><span class=\"n\">lifespan<\/span><span class=\"o\">=<\/span><span class=\"n\">lifespan<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  3. CORS Policy Blocking Requests\n<\/h3>\n\n<p><strong>Error:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Access to fetch has been blocked by CORS policy\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Solution:<\/strong><br>\nAdded frontend URL to <code>CORS_ORIGINS<\/code> in Railway:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>CORS_ORIGINS=https:\/\/ai-blog-generator.vercel.app\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  4. Environment Variables Not Loading\n<\/h3>\n\n<p><strong>Error:<\/strong><br>\nFrontend couldn't connect to backend (showing localhost URL)<\/p>\n\n<p><strong>Solution:<\/strong><br>\nEnsured <code>VITE_API_URL<\/code> was set in Vercel's environment variables for <strong>all environments<\/strong> (Production, Preview, Development).<\/p>\n<h3>\n  \n  \n  5. Hugging Face API 503 Errors\n<\/h3>\n\n<p><strong>Error:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Model is currently loading\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Solution:<\/strong><br>\nThis is expected! Hugging Face models go to sleep after inactivity. My retry logic handles it:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">if<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"n\">status_code<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">503<\/span><span class=\"p\">:<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Model loading... waiting 30 seconds<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">time<\/span><span class=\"p\">.<\/span><span class=\"nf\">sleep<\/span><span class=\"p\">(<\/span><span class=\"mi\">30<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">continue<\/span>  <span class=\"c1\"># Retry\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p>After the first request warms up the model, subsequent requests are fast.<\/p>\n\n<h2>\n  \n  \n  <img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fduuin05lqng5o64ual13.png\" alt=\"Swagger UI\" width=\"800\" height=\"402\">\n<\/h2>\n\n<h2>\n  \n  \n  Production Optimizations\n<\/h2>\n\n<h3>\n  \n  \n  Backend Optimizations\n<\/h3>\n\n<p><strong>1. Database Connection Pooling<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">engine<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">create_engine<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">settings<\/span><span class=\"p\">.<\/span><span class=\"n\">DATABASE_URL<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">pool_pre_ping<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span>    <span class=\"c1\"># Verify connections\n<\/span>    <span class=\"n\">pool_size<\/span><span class=\"o\">=<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span>          <span class=\"c1\"># Connection pool\n<\/span>    <span class=\"n\">max_overflow<\/span><span class=\"o\">=<\/span><span class=\"mi\">20<\/span>        <span class=\"c1\"># Max additional connections\n<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>2. Request Timeout Handling<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"nf\">post<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">api_url<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">headers<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">json<\/span><span class=\"o\">=<\/span><span class=\"n\">payload<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">timeout<\/span><span class=\"o\">=<\/span><span class=\"mi\">120<\/span>  <span class=\"c1\"># 2 minute timeout\n<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>3. Logging for Production<\/strong><\/p>\n\n<p>Added proper logging to track issues:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">logging<\/span>\n\n<span class=\"n\">logging<\/span><span class=\"p\">.<\/span><span class=\"nf\">basicConfig<\/span><span class=\"p\">(<\/span><span class=\"n\">level<\/span><span class=\"o\">=<\/span><span class=\"n\">logging<\/span><span class=\"p\">.<\/span><span class=\"n\">INFO<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">logger<\/span> <span class=\"o\">=<\/span> <span class=\"n\">logging<\/span><span class=\"p\">.<\/span><span class=\"nf\">getLogger<\/span><span class=\"p\">(<\/span><span class=\"n\">__name__<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># In routes\n<\/span><span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Generating blog for topic: <\/span><span class=\"si\">{<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">topic<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Generation failed: <\/span><span class=\"si\">{<\/span><span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Frontend Optimizations\n<\/h3>\n\n<p><strong>1. Environment-based API URL<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">API_BASE_URL<\/span> <span class=\"o\">=<\/span> <span class=\"k\">import<\/span><span class=\"p\">.<\/span><span class=\"nx\">meta<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">VITE_API_URL<\/span> <span class=\"o\">||<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">http:\/\/localhost:8000<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>2. Error Boundaries<\/strong><\/p>\n\n<p>Added proper error handling:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"k\">try<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">result<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">blogAPI<\/span><span class=\"p\">.<\/span><span class=\"nf\">generateBlog<\/span><span class=\"p\">(<\/span><span class=\"nx\">formData<\/span><span class=\"p\">);<\/span>\n  <span class=\"nf\">setCurrentBlog<\/span><span class=\"p\">(<\/span><span class=\"nx\">result<\/span><span class=\"p\">);<\/span>\n  <span class=\"nf\">setSuccess<\/span><span class=\"p\">(<\/span><span class=\"kc\">true<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span> <span class=\"k\">catch <\/span><span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">errorMessage<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">err<\/span><span class=\"p\">.<\/span><span class=\"nx\">response<\/span><span class=\"p\">?.<\/span><span class=\"nx\">data<\/span><span class=\"p\">?.<\/span><span class=\"nx\">detail<\/span> <span class=\"o\">||<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Failed to generate blog<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n  <span class=\"nf\">setError<\/span><span class=\"p\">(<\/span><span class=\"nx\">errorMessage<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>3. Loading States<\/strong><\/p>\n\n<p>Clear feedback during long operations:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"p\">{<\/span><span class=\"nx\">isGenerating<\/span> <span class=\"p\">?<\/span> <span class=\"p\">(<\/span>\n  <span class=\"p\">&lt;&gt;<\/span>\n\n    Generating Content...\n  <span class=\"p\">&lt;\/&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">:<\/span> <span class=\"p\">(<\/span>\n  <span class=\"p\">&lt;&gt;<\/span>\n\n    Generate Blog Post\n  <span class=\"p\">&lt;\/&gt;<\/span>\n<span class=\"p\">)}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  Cost Breakdown\n<\/h2>\n\n<p>Let's talk money - one of the best parts!<\/p>\n\n<h3>\n  \n  \n  Railway (Backend + Database)\n<\/h3>\n\n<p><strong>Hobby Plan: $5\/month<\/strong><\/p>\n\n<ul>\n<li>Includes backend hosting<\/li>\n<li>PostgreSQL database (1GB storage)<\/li>\n<li>Automatic backups<\/li>\n<li>99.9% uptime SLA<\/li>\n<\/ul>\n\n<p><strong>Free Trial:<\/strong><\/p>\n\n<ul>\n<li>$5 credit\/month for free accounts<\/li>\n<li>Perfect for side projects and portfolios<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Vercel (Frontend)\n<\/h3>\n\n<p><strong>Hobby Plan: FREE<\/strong><\/p>\n\n<ul>\n<li>Unlimited personal projects<\/li>\n<li>100GB bandwidth\/month<\/li>\n<li>Global CDN<\/li>\n<li>Automatic HTTPS<\/li>\n<li>Custom domains<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Hugging Face\n<\/h3>\n\n<p><strong>Free Tier<\/strong><\/p>\n\n<ul>\n<li>Inference API included<\/li>\n<li>Rate limits apply (but generous)<\/li>\n<li>Models sleep after inactivity<\/li>\n<li>Perfect for demos and low-traffic apps<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Total Monthly Cost\n<\/h3>\n\n<p><strong>$0 - $5\/month<\/strong> depending on Railway usage! <\/p>\n\n<p>For a production-ready, full-stack AI application, that's incredible value.<\/p>\n\n\n\n\n<h2>\n  \n  \n  CI\/CD Pipeline: Auto-Deployment\n<\/h2>\n\n<p>The best part? Both platforms auto-deploy when I push to GitHub!<\/p>\n\n<h3>\n  \n  \n  How It Works\n<\/h3>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Make changes<\/span>\ngit add <span class=\"nb\">.<\/span>\ngit commit <span class=\"nt\">-m<\/span> <span class=\"s2\">\"Add new feature\"<\/span>\ngit push origin main\n\n<span class=\"c\"># Automatically:<\/span>\n<span class=\"c\"># 1. Railway detects push<\/span>\n<span class=\"c\"># 2. Builds backend<\/span>\n<span class=\"c\"># 3. Runs tests<\/span>\n<span class=\"c\"># 4. Deploys new version<\/span>\n<span class=\"c\"># 5. Zero downtime!<\/span>\n\n<span class=\"c\"># Similarly:<\/span>\n<span class=\"c\"># 1. Vercel detects push<\/span>\n<span class=\"c\"># 2. Builds frontend<\/span>\n<span class=\"c\"># 3. Deploys to CDN<\/span>\n<span class=\"c\"># 4. Instantly live!<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Deployment time:<\/strong> 2-3 minutes for both!<\/p>\n\n<h3>\n  \n  \n  Deployment Logs\n<\/h3>\n\n<p>Railway and Vercel both provide detailed logs:<\/p>\n\n<p><strong>Railway logs showed:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Building...\n\u251c\u2500 Installing dependencies\n\u251c\u2500 Building application  \n\u2514\u2500 Starting server\n\n\u2713 Deployment successful\n\u2713 Health check passed\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Vercel logs showed:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Building...\n\u251c\u2500 Installing dependencies\n\u251c\u2500 Running build\n\u251c\u2500 Optimizing assets\n\u2514\u2500 Uploading to CDN\n\n\u2713 Build completed\n\u2713 Deployment live\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  Monitoring &amp; Maintenance\n<\/h2>\n\n<h3>\n  \n  \n  Railway Monitoring\n<\/h3>\n\n<p>Railway dashboard shows:<\/p>\n\n<ul>\n<li>\n<strong>CPU Usage:<\/strong> ~5-10% average<\/li>\n<li>\n<strong>Memory:<\/strong> ~150MB<\/li>\n<li>\n<strong>Response Times:<\/strong> 50-100ms (excluding AI)<\/li>\n<li>\n<strong>Uptime:<\/strong> 99.9%<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Vercel Analytics\n<\/h3>\n\n<p>Enabled Vercel Analytics (free!) to track:<\/p>\n\n<ul>\n<li>Page views<\/li>\n<li>User locations<\/li>\n<li>Performance metrics<\/li>\n<li>Core Web Vitals<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Database Monitoring\n<\/h3>\n\n<p>Checked PostgreSQL usage:<\/p>\n\n<ul>\n<li>\n<strong>Storage:<\/strong> ~5MB (100 blog posts)<\/li>\n<li>\n<strong>Connections:<\/strong> 2-3 active<\/li>\n<li>\n<strong>Queries:<\/strong> Fast (&lt;100ms)<\/li>\n<\/ul>\n\n<p>Everything running smoothly! <\/p>\n\n<h2>\n  \n  \n  <img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9yppnl4rj4xcvoc2leb.png\" alt=\"Dashboard\" width=\"800\" height=\"615\">\n<\/h2>\n\n<h2>\n  \n  \n  Lessons Learned\n<\/h2>\n\n<p>Here are the key takeaways from this deployment journey:<\/p>\n\n<h3>\n  \n  \n  1. <strong>Start with Simple Deployment<\/strong>\n<\/h3>\n\n<p>Don't overcomplicate. Railway and Vercel handle 90% of DevOps for you.<\/p>\n\n<h3>\n  \n  \n  2. <strong>Environment Variables Are Critical<\/strong>\n<\/h3>\n\n<p>Spent hours debugging before realizing a typo in <code>VITE_API_URL<\/code>. Triple-check these!<\/p>\n\n<h3>\n  \n  \n  3. <strong>CORS Will Get You<\/strong>\n<\/h3>\n\n<p>Always configure CORS properly. Test with actual frontend URL, not localhost.<\/p>\n\n<h3>\n  \n  \n  4. <strong>Database Initialization Matters<\/strong>\n<\/h3>\n\n<p>In production, tables won't magically appear. Handle database setup in application lifecycle.<\/p>\n\n<h3>\n  \n  \n  5. <strong>Logs Are Your Best Friend<\/strong>\n<\/h3>\n\n<p>Both Railway and Vercel have excellent logging. Use them to debug issues.<\/p>\n\n<h3>\n  \n  \n  6. <strong>Test Production Early<\/strong>\n<\/h3>\n\n<p>Deploy early, deploy often. Catching issues in production is better than finding them in interviews!<\/p>\n\n<h3>\n  \n  \n  7. <strong>Free Tiers Are Powerful<\/strong>\n<\/h3>\n\n<p>You can build and deploy production apps for $0-5\/month. No excuses!<\/p>\n\n\n\n\n<h2>\n  \n  \n  Future Improvements\n<\/h2>\n\n<p>Now that we're in production, here's what I'm planning:<\/p>\n\n<h3>\n  \n  \n  Immediate (This Week)\n<\/h3>\n\n<ul>\n<li>[ ] Add rate limiting to prevent abuse<\/li>\n<li>[ ] Set up error monitoring (Sentry)<\/li>\n<li>[ ] Add database backup automation<\/li>\n<li>[ ] Create health check monitoring<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Short-term (This Month)\n<\/h3>\n\n<ul>\n<li>[ ] Add user authentication<\/li>\n<li>[ ] Implement blog favorites<\/li>\n<li>[ ] Add export to PDF<\/li>\n<li>[ ] Create API documentation site<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Long-term (This Quarter)\n<\/h3>\n\n<ul>\n<li>[ ] Multi-language support<\/li>\n<li>[ ] Image generation for blogs<\/li>\n<li>[ ] Content scheduling<\/li>\n<li>[ ] Analytics dashboard<\/li>\n<li>[ ] WordPress integration<\/li>\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Final Thoughts\n<\/h2>\n\n<p>Deploying this project taught me more than months of tutorials ever could. <\/p>\n\n<p><strong>What worked well:<\/strong><\/p>\n\n<ul>\n<li>Railway's automatic PostgreSQL setup<\/li>\n<li>Vercel's instant deployments<\/li>\n<li>GitHub integration for CI\/CD<\/li>\n<li>Simple, clean architecture<\/li>\n<\/ul>\n\n<p><strong>What I'd do differently:<\/strong><\/p>\n\n<ul>\n<li>Set up monitoring from day one<\/li>\n<li>Add comprehensive error logging earlier<\/li>\n<li>Test with production environment variables locally<\/li>\n<li>Document deployment steps as I go<\/li>\n<\/ul>\n\n<p><strong>Most importantly:<\/strong> I now have a live, working application in my portfolio. Something I can show in interviews, share with friends, and actually use!<\/p>\n\n\n\n\n<h2>\n  \n  \n  Resources\n<\/h2>\n\n<p>Tools and platforms used:<\/p>\n\n<ul>\n<li><strong><a href=\"https:\/\/railway.app\" rel=\"noopener noreferrer\">Railway<\/a><\/strong><\/li>\n<li><strong><a href=\"https:\/\/vercel.com\" rel=\"noopener noreferrer\">Vercel<\/a><\/strong><\/li>\n<li><strong><a href=\"https:\/\/huggingface.co\" rel=\"noopener noreferrer\">Hugging Face<\/a><\/strong><\/li>\n<li>\n<strong><a href=\"https:\/\/fastapi.tiangolo.com\" rel=\"noopener noreferrer\">FastAPI<\/a><\/strong> <\/li>\n<li><strong><a href=\"https:\/\/react.dev\" rel=\"noopener noreferrer\">React<\/a><\/strong><\/li>\n<\/ul>\n\n<p>Documentation that helped:<\/p>\n\n<ul>\n<li><a href=\"https:\/\/docs.railway.app\" rel=\"noopener noreferrer\">Railway Docs<\/a><\/li>\n<li><a href=\"https:\/\/vercel.com\/docs\" rel=\"noopener noreferrer\">Vercel Docs<\/a><\/li>\n<li><a href=\"https:\/\/fastapi.tiangolo.com\/deployment\/\" rel=\"noopener noreferrer\">FastAPI Deployment<\/a><\/li>\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Try It Yourself!\n<\/h2>\n\n<p><strong><a href=\"https:\/\/frontend-ochre-rho-71.vercel.app\/\" rel=\"noopener noreferrer\">Live Demo<\/a><\/strong> <\/p>\n\n<p><strong><a href=\"https:\/\/github.com\/Lymah123\/ai-blog-generator\" rel=\"noopener noreferrer\">GitHub Repository<\/a><\/strong><\/p>\n\n<p>The complete code is open source! Feel free to:<\/p>\n\n<ul>\n<li>Star the repository<\/li>\n<li>Fork and customize<\/li>\n<li>Report issues<\/li>\n<li>Submit pull requests<\/li>\n<\/ul>\n\n<blockquote>\n<p>This project reinforced that deployment is where architectural decisions are validated\u2014and where many \u201cworking\u201d projects quietly fail<\/p>\n<\/blockquote>\n\n<h2>\n  \n  \n  \ud83d\ude4f Thank You!\n<\/h2>\n\n<p>Thanks for following along on this journey! <\/p>\n\n<p><strong><a href=\"https:\/\/dev.to\/lymah\/building-an-ai-blog-generator-with-fastapi-react-and-hugging-face-49m5\">Part 1<\/a><\/strong> covered the development process.<br><br>\n<strong>Part 2<\/strong> (this post) covered deployment.<\/p>\n\n<p>What did you learn? What would you do differently? Drop a comment below!<\/p>\n\n<p>If you found this helpful:<\/p>\n\n<ul>\n<li>\u2764\ufe0f Like this post<\/li>\n<li>\ud83d\udcac Leave a comment<\/li>\n<li>\ud83d\udd04 Share with others<\/li>\n<li>\ud83d\udc40 Follow me for more content<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Connect With Me\n<\/h2>\n\n<p>I'd love to hear your thoughts and answer questions!<\/p>\n\n<ul>\n<li><strong><a href=\"https:\/\/github.com\/Lymah123\" rel=\"noopener noreferrer\">GitHub<\/a><\/strong><\/li>\n<li><strong><a href=\"https:\/\/twitter.com\/CodesLymah\" rel=\"noopener noreferrer\">Twitter(X)<\/a><\/strong><\/li>\n<li><strong><a href=\"https:\/\/www.linkedin.com\/in\/harlimat-odunola-2ab261235\" rel=\"noopener noreferrer\">LinkedIn<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  What's Next?\n<\/h2>\n\n<p>I'm already working on v2.0 with exciting features:<\/p>\n\n<ul>\n<li>\ud83d\udd10 User authentication<\/li>\n<li>\ud83d\uddbc\ufe0f AI-generated blog images<\/li>\n<li>\ud83d\udcc5 Content scheduling<\/li>\n<li>\ud83d\udcca Analytics dashboard<\/li>\n<\/ul>\n\n<p><strong>Stay tuned!<\/strong> Follow me to get notified when the next update drops.<\/p>\n\n","category":["deployment","devops","railway","vercel"]},{"title":"Building an AI Blog Generator with FastAPI, React, and Hugging Face","pubDate":"Wed, 14 Jan 2026 04:06:20 +0000","link":"https:\/\/dev.to\/lymah\/building-an-ai-blog-generator-with-fastapi-react-and-hugging-face-49m5","guid":"https:\/\/dev.to\/lymah\/building-an-ai-blog-generator-with-fastapi-react-and-hugging-face-49m5","description":"<p><em>How I built a production-ready AI application that generates SEO-optimized blog posts in 30 seconds<\/em><\/p>\n\n<h2>\n  \n  \n  Why I Built This\n<\/h2>\n\n<p>I'll be honest with you - I've spent countless hours staring at blank screens, struggling to write blog posts. As a developer who loves building things but finds writing challenging, I often thought: <strong>\"What if I could generate high-quality blog drafts in seconds?\"<\/strong><\/p>\n\n<p>That question led me down a rabbit hole that resulted in building a complete AI-powered blog generator from scratch. This isn't just another AI wrapper - it's a full-stack application with custom prompt engineering, SEO optimization, and a beautiful user interface.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>## Who This Is For\n\nThis article is for you if:\n- You\u2019re a backend developer curious about AI integration\n- You want to see how AI fits into a real production system\n- You care about structure, validation, and maintainability\n- You\u2019re learning React but primarily think in backend terms\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>What we're building:<\/strong><\/p>\n\n<ul>\n<li>AI-powered blog generation (600-2500 words)<\/li>\n<li>Multiple writing tones (Professional, Casual, Technical, Educational)<\/li>\n<li>Automatic SEO scoring and keyword optimization<\/li>\n<li>PostgreSQL database for content management<\/li>\n<li>Beautiful, responsive React UI with Tailwind CSS<\/li>\n<\/ul>\n\n<p>This is <strong>Part 1<\/strong> of a two-part series. Today, we'll dive deep into the development process. Part 2 will cover deployment to production.<\/p>\n\n<p><a href=\"https:\/\/github.com\/Lymah123\/ai-blog-generator\" rel=\"noopener noreferrer\">GitHub Repository<\/a><\/p>\n\n\n\n\n<h2>\n  \n  \n  Tech Stack: Why These Choices?\n<\/h2>\n\n<p>Let me walk you through my technical decisions and the reasoning behind them.<\/p>\n\n<h3>\n  \n  \n  Backend: FastAPI\n<\/h3>\n\n<p>I chose <strong>FastAPI<\/strong> over Flask or Django for several compelling reasons:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">fastapi<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">FastAPI<\/span><span class=\"p\">,<\/span> <span class=\"n\">HTTPException<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">pydantic<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">BaseModel<\/span>\n\n<span class=\"c1\"># Type-safe, auto-documented, and blazing fast\n<\/span><span class=\"k\">class<\/span> <span class=\"nc\">BlogRequest<\/span><span class=\"p\">(<\/span><span class=\"n\">BaseModel<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">topic<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span>\n    <span class=\"n\">tone<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">professional<\/span><span class=\"sh\">\"<\/span>\n    <span class=\"n\">length<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">medium<\/span><span class=\"sh\">\"<\/span>\n    <span class=\"n\">keywords<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">|<\/span> <span class=\"bp\">None<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span>\n\n<span class=\"nd\">@app.post<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\/generate<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">generate_blog<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">:<\/span> <span class=\"n\">BlogRequest<\/span><span class=\"p\">):<\/span>\n    <span class=\"c1\"># FastAPI handles validation automatically\n<\/span>    <span class=\"k\">return<\/span> <span class=\"k\">await<\/span> <span class=\"n\">ai_service<\/span><span class=\"p\">.<\/span><span class=\"nf\">generate<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why FastAPI?<\/strong><\/p>\n\n<ul>\n<li>\n<strong>Performance<\/strong>: Built on Starlette, it's one of the fastest Python frameworks<\/li>\n<li>\n<strong>Auto Docs<\/strong>: Interactive API documentation (Swagger UI) out of the box<\/li>\n<li>\n<strong>Type Safety<\/strong>: Pydantic validation catches errors before they happen<\/li>\n<li>\n<strong>Modern<\/strong>: Native async\/await support, perfect for AI API calls<\/li>\n<li>\n<strong>Developer Experience<\/strong>: Clear error messages and intuitive API design<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Frontend: React + Vite + Tailwind\n<\/h3>\n\n<p><strong>React<\/strong> for the component-based architecture and ecosystem.<\/p>\n\n<p><strong>Vite<\/strong> instead of Create React App because:<\/p>\n\n<ul>\n<li>Instant server start<\/li>\n<li>Lightning-fast hot module replacement<\/li>\n<li>Optimized production build<\/li>\n<\/ul>\n\n<p><strong>Tailwind CSS<\/strong> for rapid, maintainable styling:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"c1\">\/\/ Clean, utility-first styling<\/span>\n\n  <span class=\"nx\">Generate<\/span> <span class=\"nx\">Blog<\/span> <span class=\"nx\">Post<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  AI: Hugging Face Transformers\n<\/h3>\n\n<p>I chose <strong>Hugging Face<\/strong> over OpenAI for several reasons:<\/p>\n\n<ul>\n<li>\n<strong>Cost<\/strong>: More affordable for experimentation<\/li>\n<li>\n<strong>Open Models<\/strong>: Access to open-source models like Llama<\/li>\n<li>\n<strong>Control<\/strong>: Full control over model selection and parameters<\/li>\n<li>\n<strong>Transparency<\/strong>: Clear understanding of what's happening under the hood<\/li>\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Architecture: How It All Fits Together\n<\/h2>\n\n<p>Here's the high-level architecture:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                 \u2502         \u2502                  \u2502         \u2502                 \u2502\n\u2502  React Frontend \u2502\u25c4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba\u2502  FastAPI Backend \u2502\u25c4\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba\u2502   PostgreSQL    \u2502\n\u2502   (Port 5173)   \u2502   HTTP  \u2502   (Port 8000)    \u2502   ORM   \u2502    Database     \u2502\n\u2502                 \u2502         \u2502                  \u2502         \u2502                 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                     \u2502\n                                     \u2502 HTTPS\n                                     \u25bc\n                            \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                            \u2502  Hugging Face    \u2502\n                            \u2502  Inference API   \u2502\n                            \u2502 (Llama 3.3 70B)  \u2502\n                            \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Data Flow:<\/strong><\/p>\n\n<ol>\n<li>User fills form \u2192 Frontend validation<\/li>\n<li>POST request to <code>\/api\/v1\/generate<\/code> \u2192 Backend receives data<\/li>\n<li>Backend builds optimized prompt \u2192 Calls Hugging Face API<\/li>\n<li>AI generates content \u2192 Backend processes and cleans output<\/li>\n<li>Calculate SEO score \u2192 Save to PostgreSQL<\/li>\n<li>Return formatted blog \u2192 Frontend displays result<\/li>\n<\/ol>\n\n\n\n\n<h2>\n  \n  \n  Backend Deep Dive\n<\/h2>\n\n<h3>\n  \n  \n  Project Structure\n<\/h3>\n\n<p>I organized the backend following a clean architecture pattern:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>backend\/\n\u251c\u2500\u2500 app\/\n\u2502   \u251c\u2500\u2500 main.py                 # FastAPI app initialization\n\u2502   \u251c\u2500\u2500 config.py               # Environment configuration\n\u2502   \u251c\u2500\u2500 database.py             # Database connection\n\u2502   \u251c\u2500\u2500 models\/\n\u2502   \u2502   \u2514\u2500\u2500 blog.py             # SQLAlchemy models\n\u2502   \u251c\u2500\u2500 schemas\/\n\u2502   \u2502   \u2514\u2500\u2500 blog.py             # Pydantic schemas\n\u2502   \u251c\u2500\u2500 api\/\n\u2502   \u2502   \u2514\u2500\u2500 routes.py           # API endpoints\n\u2502   \u251c\u2500\u2500 services\/\n\u2502   \u2502   \u251c\u2500\u2500 ai_service.py       # Hugging Face integration\n\u2502   \u2502   \u2514\u2500\u2500 seo_service.py      # SEO scoring logic\n\u2502   \u2514\u2500\u2500 utils\/\n\u2502       \u2514\u2500\u2500 post_processor.py   # Content processing\n\u2514\u2500\u2500 requirements.txt\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgn7se13hc8rfsfdpaa6.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgn7se13hc8rfsfdpaa6.png\" alt=\"API respone\" width=\"800\" height=\"450\"><\/a><\/p>\n\n<h3>\n  \n  \n  1. Database Models with SQLAlchemy\n<\/h3>\n\n<p>First, I defined the database schema for storing blog posts:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># app\/models\/blog.py\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">sqlalchemy<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Column<\/span><span class=\"p\">,<\/span> <span class=\"n\">Integer<\/span><span class=\"p\">,<\/span> <span class=\"n\">String<\/span><span class=\"p\">,<\/span> <span class=\"n\">Text<\/span><span class=\"p\">,<\/span> <span class=\"n\">DateTime<\/span><span class=\"p\">,<\/span> <span class=\"n\">Float<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">sqlalchemy.sql<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">func<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">app.database<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Base<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">BlogPost<\/span><span class=\"p\">(<\/span><span class=\"n\">Base<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">__tablename__<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">blog_posts<\/span><span class=\"sh\">\"<\/span>\n\n    <span class=\"nb\">id<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"n\">Integer<\/span><span class=\"p\">,<\/span> <span class=\"n\">primary_key<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">index<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">topic<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"p\">(<\/span><span class=\"mi\">500<\/span><span class=\"p\">),<\/span> <span class=\"n\">nullable<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">,<\/span> <span class=\"n\">index<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">tone<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"p\">(<\/span><span class=\"mi\">50<\/span><span class=\"p\">),<\/span> <span class=\"n\">nullable<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">length<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"p\">(<\/span><span class=\"mi\">20<\/span><span class=\"p\">),<\/span> <span class=\"n\">nullable<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">keywords<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"n\">Text<\/span><span class=\"p\">,<\/span> <span class=\"n\">nullable<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">title<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"nc\">String<\/span><span class=\"p\">(<\/span><span class=\"mi\">500<\/span><span class=\"p\">),<\/span> <span class=\"n\">nullable<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">content<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"n\">Text<\/span><span class=\"p\">,<\/span> <span class=\"n\">nullable<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">seo_score<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"n\">Float<\/span><span class=\"p\">,<\/span> <span class=\"n\">nullable<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">word_count<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"n\">Integer<\/span><span class=\"p\">,<\/span> <span class=\"n\">nullable<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">created_at<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Column<\/span><span class=\"p\">(<\/span><span class=\"nc\">DateTime<\/span><span class=\"p\">(<\/span><span class=\"n\">timezone<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">),<\/span> <span class=\"n\">server_default<\/span><span class=\"o\">=<\/span><span class=\"n\">func<\/span><span class=\"p\">.<\/span><span class=\"nf\">now<\/span><span class=\"p\">())<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why this structure?<\/strong><\/p>\n\n<ul>\n<li>Indexed fields (<code>topic<\/code>, <code>id<\/code>) for faster queries<\/li>\n<li>Flexible <code>keywords<\/code> as Text for comma-separated values<\/li>\n<li>Timestamps for tracking creation<\/li>\n<li>SEO score as Float for decimal precision<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  2. Pydantic Schemas for Validation\n<\/h3>\n\n<p>Type-safe request\/response models:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># app\/schemas\/blog.py\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">pydantic<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">BaseModel<\/span><span class=\"p\">,<\/span> <span class=\"n\">Field<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">typing<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Optional<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">BlogGenerateRequest<\/span><span class=\"p\">(<\/span><span class=\"n\">BaseModel<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">topic<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Field<\/span><span class=\"p\">(...,<\/span> <span class=\"n\">min_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">5<\/span><span class=\"p\">,<\/span> <span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">500<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">tone<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Field<\/span><span class=\"p\">(<\/span><span class=\"n\">default<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">professional<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">length<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Field<\/span><span class=\"p\">(<\/span><span class=\"n\">default<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">medium<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">keywords<\/span><span class=\"p\">:<\/span> <span class=\"n\">Optional<\/span><span class=\"p\">[<\/span><span class=\"nb\">str<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Field<\/span><span class=\"p\">(<\/span><span class=\"bp\">None<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">class<\/span> <span class=\"nc\">Config<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">json_schema_extra<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">example<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">topic<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">The Future of AI<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">tone<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">professional<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">length<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">medium<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">keywords<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">AI, machine learning, automation<\/span><span class=\"sh\">\"<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">BlogResponse<\/span><span class=\"p\">(<\/span><span class=\"n\">BaseModel<\/span><span class=\"p\">):<\/span>\n    <span class=\"nb\">id<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span>\n    <span class=\"n\">topic<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span>\n    <span class=\"n\">title<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span>\n    <span class=\"n\">content<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span>\n    <span class=\"n\">seo_score<\/span><span class=\"p\">:<\/span> <span class=\"nb\">float<\/span>\n    <span class=\"n\">word_count<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span>\n    <span class=\"n\">created_at<\/span><span class=\"p\">:<\/span> <span class=\"n\">datetime<\/span>\n\n    <span class=\"k\">class<\/span> <span class=\"nc\">Config<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">from_attributes<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">True<\/span>  <span class=\"c1\"># Enable ORM mode\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>The beauty of Pydantic:<\/strong><\/p>\n\n<ul>\n<li>Automatic validation on incoming requests<\/li>\n<li>Clear error messages if validation fails<\/li>\n<li>Auto-generated API documentation<\/li>\n<li>Type hints everywhere<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  3. AI Service: The Heart of the Application\n<\/h3>\n\n<p>This is where the magic happens. Here's my Hugging Face integration:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># app\/services\/ai_service.py\n<\/span><span class=\"kn\">import<\/span> <span class=\"n\">requests<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">time<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">typing<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Dict<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">HuggingFaceService<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">__init__<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">api_url<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/router.huggingface.co\/v1\/chat\/completions<\/span><span class=\"sh\">\"<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">headers<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">Authorization<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Bearer <\/span><span class=\"si\">{<\/span><span class=\"n\">settings<\/span><span class=\"p\">.<\/span><span class=\"n\">HUGGINGFACE_API_KEY<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">Content-Type<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">application\/json<\/span><span class=\"sh\">\"<\/span>\n        <span class=\"p\">}<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">generate_blog<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">topic<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">tone<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">length<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> \n                     <span class=\"n\">keywords<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n        <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Main entry point for blog generation<\/span><span class=\"sh\">\"\"\"<\/span>\n\n        <span class=\"c1\"># 1. Build optimized prompt\n<\/span>        <span class=\"n\">prompt<\/span> <span class=\"o\">=<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"nf\">_build_prompt<\/span><span class=\"p\">(<\/span><span class=\"n\">topic<\/span><span class=\"p\">,<\/span> <span class=\"n\">tone<\/span><span class=\"p\">,<\/span> <span class=\"n\">length<\/span><span class=\"p\">,<\/span> <span class=\"n\">keywords<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\"># 2. Call Hugging Face API\n<\/span>        <span class=\"n\">raw_content<\/span> <span class=\"o\">=<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"nf\">_call_api<\/span><span class=\"p\">(<\/span><span class=\"n\">prompt<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\"># 3. Post-process content\n<\/span>        <span class=\"n\">cleaned<\/span> <span class=\"o\">=<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">post_processor<\/span><span class=\"p\">.<\/span><span class=\"nf\">clean_content<\/span><span class=\"p\">(<\/span><span class=\"n\">raw_content<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">title<\/span><span class=\"p\">,<\/span> <span class=\"n\">content<\/span> <span class=\"o\">=<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">post_processor<\/span><span class=\"p\">.<\/span><span class=\"nf\">extract_title_and_content<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">cleaned<\/span><span class=\"p\">,<\/span> <span class=\"n\">topic<\/span>\n        <span class=\"p\">)<\/span>\n\n        <span class=\"c1\"># 4. Calculate metrics\n<\/span>        <span class=\"n\">word_count<\/span> <span class=\"o\">=<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">post_processor<\/span><span class=\"p\">.<\/span><span class=\"nf\">count_words<\/span><span class=\"p\">(<\/span><span class=\"n\">content<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">seo_score<\/span> <span class=\"o\">=<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">seo_service<\/span><span class=\"p\">.<\/span><span class=\"nf\">calculate_score<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">content<\/span><span class=\"p\">,<\/span> <span class=\"n\">title<\/span><span class=\"p\">,<\/span> <span class=\"n\">keywords<\/span>\n        <span class=\"p\">)<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">title<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">title<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">content<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">content<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">word_count<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">word_count<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">seo_score<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">seo_score<\/span>\n        <span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Prompt Engineering: The Secret Sauce\n<\/h4>\n\n<p>Building effective prompts was crucial. Here's my approach:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">def<\/span> <span class=\"nf\">_build_prompt<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">topic<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">tone<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">length<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> \n                  <span class=\"n\">keywords<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Construct optimized prompt for blog generation<\/span><span class=\"sh\">\"\"\"<\/span>\n\n    <span class=\"n\">tone_map<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">professional<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">authoritative, polished, business-appropriate<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">casual<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">friendly, conversational, relatable<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">technical<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">detailed, precise, technically accurate<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">educational<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">clear, informative, easy to understand<\/span><span class=\"sh\">\"<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"n\">length_map<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">short<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">600-800 words<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">medium<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">1000-1500 words<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">long<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">1800-2500 words<\/span><span class=\"sh\">\"<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">You are an expert blog writer. Write a comprehensive blog post.\n\n**Topic:** <\/span><span class=\"si\">{<\/span><span class=\"n\">topic<\/span><span class=\"si\">}<\/span><span class=\"s\">\n**Tone:** <\/span><span class=\"si\">{<\/span><span class=\"n\">tone_map<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">tone<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\">\n**Target Length:** <\/span><span class=\"si\">{<\/span><span class=\"n\">length_map<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">length<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\">\n<\/span><span class=\"si\">{<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">**Keywords<\/span><span class=\"si\">:<\/span><span class=\"o\">**<\/span> <span class=\"si\">{<\/span><span class=\"n\">keywords<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"s\"> if keywords else <\/span><span class=\"sh\">\"\"<\/span><span class=\"si\">}<\/span><span class=\"s\">\n\n**Requirements:**\n1. Create an engaging, SEO-friendly title\n2. Write a compelling introduction\n3. Use clear subheadings (## for H2)\n4. Include practical examples\n5. End with a strong conclusion\n\n**Format:**\n# [Title]\n\n[Introduction]\n\n## [Section 1]\n[Content]\n\n## [Section 2]\n[Content]\n\n## Conclusion\n[Summary]\n\nWrite the blog post now:<\/span><span class=\"sh\">\"\"\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why this prompt works:<\/strong><\/p>\n\n<ul>\n<li>Clear structure and expectations<\/li>\n<li>Specific tone guidance<\/li>\n<li>Explicit formatting requirements<\/li>\n<li>Target word count for consistency<\/li>\n<li>Keyword integration instructions<\/li>\n<\/ul>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9ts5x3k6bzez94irqox.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9ts5x3k6bzez94irqox.png\" alt=\"Backend docs\" width=\"800\" height=\"402\"><\/a><\/p>\n\n<h4>\n  \n  \n  API Call with Retry Logic\n<\/h4>\n\n<p>Hugging Face models can take time to load (503 errors). Here's my retry logic:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">def<\/span> <span class=\"nf\">_call_api<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">prompt<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">max_retries<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Call HF API with retry logic<\/span><span class=\"sh\">\"\"\"<\/span>\n\n    <span class=\"n\">payload<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">model<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">meta-llama\/Llama-3.3-70B-Instruct<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">messages<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n            <span class=\"p\">{<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">role<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">system<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">content<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">You are an expert blog writer.<\/span><span class=\"sh\">\"<\/span>\n            <span class=\"p\">},<\/span>\n            <span class=\"p\">{<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">role<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">user<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">content<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">prompt<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">],<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">max_tokens<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"mi\">2500<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">temperature<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"mf\">0.7<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">top_p<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"mf\">0.9<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">for<\/span> <span class=\"n\">attempt<\/span> <span class=\"ow\">in<\/span> <span class=\"nf\">range<\/span><span class=\"p\">(<\/span><span class=\"n\">max_retries<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"nf\">post<\/span><span class=\"p\">(<\/span>\n                <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">api_url<\/span><span class=\"p\">,<\/span>\n                <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">headers<\/span><span class=\"p\">,<\/span>\n                <span class=\"n\">json<\/span><span class=\"o\">=<\/span><span class=\"n\">payload<\/span><span class=\"p\">,<\/span>\n                <span class=\"n\">timeout<\/span><span class=\"o\">=<\/span><span class=\"mi\">120<\/span>  <span class=\"c1\"># 2 minute timeout\n<\/span>            <span class=\"p\">)<\/span>\n\n            <span class=\"c1\"># Model loading, wait and retry\n<\/span>            <span class=\"k\">if<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"n\">status_code<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">503<\/span><span class=\"p\">:<\/span>\n                <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Model loading... waiting 30 seconds<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n                <span class=\"n\">time<\/span><span class=\"p\">.<\/span><span class=\"nf\">sleep<\/span><span class=\"p\">(<\/span><span class=\"mi\">30<\/span><span class=\"p\">)<\/span>\n                <span class=\"k\">continue<\/span>\n\n            <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">raise_for_status<\/span><span class=\"p\">()<\/span>\n            <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">json<\/span><span class=\"p\">()<\/span>\n\n            <span class=\"k\">return<\/span> <span class=\"n\">result<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">choices<\/span><span class=\"sh\">\"<\/span><span class=\"p\">][<\/span><span class=\"mi\">0<\/span><span class=\"p\">][<\/span><span class=\"sh\">\"<\/span><span class=\"s\">message<\/span><span class=\"sh\">\"<\/span><span class=\"p\">][<\/span><span class=\"sh\">\"<\/span><span class=\"s\">content<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span>\n\n        <span class=\"k\">except<\/span> <span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"n\">exceptions<\/span><span class=\"p\">.<\/span><span class=\"n\">Timeout<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">if<\/span> <span class=\"n\">attempt<\/span> <span class=\"o\">&lt;<\/span> <span class=\"n\">max_retries<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">time<\/span><span class=\"p\">.<\/span><span class=\"nf\">sleep<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">)<\/span>\n                <span class=\"k\">continue<\/span>\n            <span class=\"k\">raise<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Request timed out<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">raise<\/span> <span class=\"nc\">Exception<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Failed after multiple retries<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Key points:<\/strong><\/p>\n\n<ul>\n<li>503 handling for model warm-up<\/li>\n<li>Exponential backoff between retries<\/li>\n<li>Proper timeout handling<\/li>\n<li>Clear error messages<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  4. SEO Scoring Algorithm\n<\/h3>\n\n<p>I built a custom SEO scoring system that evaluates multiple factors:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># app\/services\/seo_service.py\n<\/span><span class=\"kn\">import<\/span> <span class=\"n\">re<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">SEOService<\/span><span class=\"p\">:<\/span>\n    <span class=\"nd\">@staticmethod<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">calculate_score<\/span><span class=\"p\">(<\/span><span class=\"n\">content<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">title<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> \n                       <span class=\"n\">keywords<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">float<\/span><span class=\"p\">:<\/span>\n        <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Calculate SEO score (0-100)<\/span><span class=\"sh\">\"\"\"<\/span>\n        <span class=\"n\">score<\/span> <span class=\"o\">=<\/span> <span class=\"mf\">0.0<\/span>\n\n        <span class=\"c1\"># 1. Word Count Analysis (25 points)\n<\/span>        <span class=\"n\">word_count<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">findall<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">\\b\\w+\\b<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">content<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">if<\/span> <span class=\"mi\">800<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"n\">word_count<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"mi\">2500<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">25<\/span>\n        <span class=\"k\">elif<\/span> <span class=\"mi\">600<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"n\">word_count<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">800<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">18<\/span>\n        <span class=\"k\">elif<\/span> <span class=\"n\">word_count<\/span> <span class=\"o\">&gt;=<\/span> <span class=\"mi\">500<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">12<\/span>\n\n        <span class=\"c1\"># 2. Title Optimization (15 points)\n<\/span>        <span class=\"k\">if<\/span> <span class=\"n\">title<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">title_length<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">title<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">if<\/span> <span class=\"mi\">40<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"n\">title_length<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"mi\">70<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">15<\/span>\n            <span class=\"k\">elif<\/span> <span class=\"mi\">30<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"n\">title_length<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">40<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">10<\/span>\n            <span class=\"k\">elif<\/span> <span class=\"n\">title_length<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">5<\/span>\n\n        <span class=\"c1\"># 3. Heading Structure (20 points)\n<\/span>        <span class=\"n\">h2_count<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">findall<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">##\\s+<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">content<\/span><span class=\"p\">))<\/span>\n        <span class=\"n\">h3_count<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">findall<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">###\\s+<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">content<\/span><span class=\"p\">))<\/span>\n        <span class=\"n\">total_headings<\/span> <span class=\"o\">=<\/span> <span class=\"n\">h2_count<\/span> <span class=\"o\">+<\/span> <span class=\"n\">h3_count<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"mi\">3<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"n\">total_headings<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"mi\">8<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">20<\/span>\n        <span class=\"k\">elif<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"n\">total_headings<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"mi\">10<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">15<\/span>\n        <span class=\"k\">elif<\/span> <span class=\"n\">total_headings<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">8<\/span>\n\n        <span class=\"c1\"># 4. Keyword Optimization (25 points)\n<\/span>        <span class=\"k\">if<\/span> <span class=\"n\">keywords<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">keyword_list<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">k<\/span><span class=\"p\">.<\/span><span class=\"nf\">strip<\/span><span class=\"p\">().<\/span><span class=\"nf\">lower<\/span><span class=\"p\">()<\/span> \n                          <span class=\"k\">for<\/span> <span class=\"n\">k<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">keywords<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">,<\/span><span class=\"sh\">'<\/span><span class=\"p\">)]<\/span>\n            <span class=\"n\">content_lower<\/span> <span class=\"o\">=<\/span> <span class=\"n\">content<\/span><span class=\"p\">.<\/span><span class=\"nf\">lower<\/span><span class=\"p\">()<\/span>\n            <span class=\"n\">title_lower<\/span> <span class=\"o\">=<\/span> <span class=\"n\">title<\/span><span class=\"p\">.<\/span><span class=\"nf\">lower<\/span><span class=\"p\">()<\/span> <span class=\"k\">if<\/span> <span class=\"n\">title<\/span> <span class=\"k\">else<\/span> <span class=\"sh\">\"\"<\/span>\n\n            <span class=\"c1\"># Keywords in content\n<\/span>            <span class=\"n\">keywords_in_content<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">sum<\/span><span class=\"p\">(<\/span>\n                <span class=\"mi\">1<\/span> <span class=\"k\">for<\/span> <span class=\"n\">kw<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">keyword_list<\/span> <span class=\"k\">if<\/span> <span class=\"n\">kw<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">content_lower<\/span>\n            <span class=\"p\">)<\/span>\n            <span class=\"k\">if<\/span> <span class=\"n\">keywords_in_content<\/span> <span class=\"o\">&gt;=<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">keyword_list<\/span><span class=\"p\">):<\/span>\n                <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">15<\/span>\n            <span class=\"k\">elif<\/span> <span class=\"n\">keywords_in_content<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">8<\/span>\n\n            <span class=\"c1\"># Keywords in title\n<\/span>            <span class=\"n\">keywords_in_title<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">sum<\/span><span class=\"p\">(<\/span>\n                <span class=\"mi\">1<\/span> <span class=\"k\">for<\/span> <span class=\"n\">kw<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">keyword_list<\/span> <span class=\"k\">if<\/span> <span class=\"n\">kw<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">title_lower<\/span>\n            <span class=\"p\">)<\/span>\n            <span class=\"k\">if<\/span> <span class=\"n\">keywords_in_title<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">10<\/span>\n        <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">12<\/span>  <span class=\"c1\"># Partial credit\n<\/span>\n        <span class=\"c1\"># 5. Content Structure (15 points)\n<\/span>        <span class=\"n\">has_intro<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">bool<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">search<\/span><span class=\"p\">(<\/span>\n            <span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">(introduction|overview)<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> \n            <span class=\"n\">content<\/span><span class=\"p\">.<\/span><span class=\"nf\">lower<\/span><span class=\"p\">()[:<\/span><span class=\"mi\">500<\/span><span class=\"p\">]<\/span>\n        <span class=\"p\">))<\/span>\n        <span class=\"n\">has_conclusion<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">bool<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">search<\/span><span class=\"p\">(<\/span>\n            <span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">(conclusion|summary|final)<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> \n            <span class=\"n\">content<\/span><span class=\"p\">.<\/span><span class=\"nf\">lower<\/span><span class=\"p\">()[<\/span><span class=\"o\">-<\/span><span class=\"mi\">500<\/span><span class=\"p\">:]<\/span>\n        <span class=\"p\">))<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"n\">has_intro<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">7<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">has_conclusion<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">score<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">8<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"nf\">min<\/span><span class=\"p\">(<\/span><span class=\"nf\">round<\/span><span class=\"p\">(<\/span><span class=\"n\">score<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">),<\/span> <span class=\"mf\">100.0<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Scoring breakdown:<\/strong><\/p>\n\n<ul>\n<li>25 points: Optimal word count (800-2500)<\/li>\n<li>15 points: Title length optimization<\/li>\n<li>20 points: Proper heading structure<\/li>\n<li>25 points: Keyword usage and placement<\/li>\n<li>15 points: Content structure (intro\/conclusion)<\/li>\n<\/ul>\n\n<p>This gives us a fair, multi-dimensional quality score.<\/p>\n\n<h3>\n  \n  \n  5. Post-Processing Pipeline\n<\/h3>\n\n<p>Raw AI output needs cleaning. Here's my post-processor:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># app\/utils\/post_processor.py\n<\/span><span class=\"kn\">import<\/span> <span class=\"n\">re<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">typing<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Tuple<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">PostProcessor<\/span><span class=\"p\">:<\/span>\n    <span class=\"nd\">@staticmethod<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">clean_content<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n        <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Clean and format generated text<\/span><span class=\"sh\">\"\"\"<\/span>\n        <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">text<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"sh\">\"\"<\/span>\n\n        <span class=\"c1\"># Remove excessive whitespace\n<\/span>        <span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">sub<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">\\n{3,}<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"se\">\\n\\n<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">sub<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\"> {2,}<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\"> <\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"n\">text<\/span><span class=\"p\">.<\/span><span class=\"nf\">strip<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"nd\">@staticmethod<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">extract_title_and_content<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> \n                                  <span class=\"n\">fallback_topic<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Tuple<\/span><span class=\"p\">[<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"nb\">str<\/span><span class=\"p\">]:<\/span>\n        <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Extract title from content<\/span><span class=\"sh\">\"\"\"<\/span>\n        <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">text<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">fallback_topic<\/span><span class=\"si\">}<\/span><span class=\"s\">: A Comprehensive Guide<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"\"<\/span>\n\n        <span class=\"n\">lines<\/span> <span class=\"o\">=<\/span> <span class=\"n\">text<\/span><span class=\"p\">.<\/span><span class=\"nf\">split<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"se\">\\n<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">title<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span>\n        <span class=\"n\">content_lines<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n\n        <span class=\"k\">for<\/span> <span class=\"n\">line<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">lines<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">line<\/span> <span class=\"o\">=<\/span> <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"nf\">strip<\/span><span class=\"p\">()<\/span>\n\n            <span class=\"c1\"># Look for title (lines starting with #)\n<\/span>            <span class=\"k\">if<\/span> <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"nf\">startswith<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\"># <\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span> <span class=\"ow\">and<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">title<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">title<\/span> <span class=\"o\">=<\/span> <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"nf\">replace<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\"># <\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">''<\/span><span class=\"p\">).<\/span><span class=\"nf\">strip<\/span><span class=\"p\">()<\/span>\n            <span class=\"k\">elif<\/span> <span class=\"n\">line<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">content_lines<\/span><span class=\"p\">.<\/span><span class=\"nf\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">line<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"c1\"># Fallback title if none found\n<\/span>        <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">title<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">title<\/span> <span class=\"o\">=<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">fallback_topic<\/span><span class=\"si\">}<\/span><span class=\"s\">: A Comprehensive Guide<\/span><span class=\"sh\">\"<\/span>\n\n        <span class=\"n\">content<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"se\">\\n\\n<\/span><span class=\"sh\">'<\/span><span class=\"p\">.<\/span><span class=\"nf\">join<\/span><span class=\"p\">(<\/span><span class=\"n\">content_lines<\/span><span class=\"p\">)<\/span> <span class=\"k\">if<\/span> <span class=\"n\">content_lines<\/span> <span class=\"k\">else<\/span> <span class=\"n\">text<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"n\">title<\/span><span class=\"p\">,<\/span> <span class=\"n\">content<\/span>\n\n    <span class=\"nd\">@staticmethod<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">count_words<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Count words accurately<\/span><span class=\"sh\">\"\"\"<\/span>\n        <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">text<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"mi\">0<\/span>\n        <span class=\"n\">words<\/span> <span class=\"o\">=<\/span> <span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">findall<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">\\b\\w+\\b<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">words<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why post-processing matters:<\/strong><\/p>\n\n<ul>\n<li>AI output isn't always perfectly formatted<\/li>\n<li>Need to extract structured data (title, content)<\/li>\n<li>Clean up artifacts and inconsistencies<\/li>\n<li>Ensure consistent formatting<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  6. API Routes: Putting It All Together\n<\/h3>\n\n<p>Finally, the API endpoints that tie everything together:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># app\/api\/routes.py\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">fastapi<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">APIRouter<\/span><span class=\"p\">,<\/span> <span class=\"n\">Depends<\/span><span class=\"p\">,<\/span> <span class=\"n\">HTTPException<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">sqlalchemy.orm<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Session<\/span>\n\n<span class=\"n\">router<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">APIRouter<\/span><span class=\"p\">()<\/span>\n\n<span class=\"nd\">@router.post<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\/generate<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">response_model<\/span><span class=\"o\">=<\/span><span class=\"n\">BlogResponse<\/span><span class=\"p\">,<\/span> <span class=\"n\">status_code<\/span><span class=\"o\">=<\/span><span class=\"mi\">201<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">generate_blog<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">request<\/span><span class=\"p\">:<\/span> <span class=\"n\">BlogGenerateRequest<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">db<\/span><span class=\"p\">:<\/span> <span class=\"n\">Session<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Depends<\/span><span class=\"p\">(<\/span><span class=\"n\">get_db<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">):<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Generate a new blog post using AI<\/span><span class=\"sh\">\"\"\"<\/span>\n\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"c1\"># Generate content\n<\/span>        <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"n\">hf_service<\/span><span class=\"p\">.<\/span><span class=\"nf\">generate_blog<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">topic<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">topic<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">tone<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">tone<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">length<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">length<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">keywords<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">keywords<\/span>\n        <span class=\"p\">)<\/span>\n\n        <span class=\"c1\"># Save to database\n<\/span>        <span class=\"n\">blog_post<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">BlogPost<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">topic<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">topic<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">tone<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">tone<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">length<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">length<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">keywords<\/span><span class=\"o\">=<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">keywords<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">title<\/span><span class=\"o\">=<\/span><span class=\"n\">result<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">title<\/span><span class=\"sh\">\"<\/span><span class=\"p\">],<\/span>\n            <span class=\"n\">content<\/span><span class=\"o\">=<\/span><span class=\"n\">result<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">content<\/span><span class=\"sh\">\"<\/span><span class=\"p\">],<\/span>\n            <span class=\"n\">word_count<\/span><span class=\"o\">=<\/span><span class=\"n\">result<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">word_count<\/span><span class=\"sh\">\"<\/span><span class=\"p\">],<\/span>\n            <span class=\"n\">seo_score<\/span><span class=\"o\">=<\/span><span class=\"n\">result<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">seo_score<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span>\n        <span class=\"p\">)<\/span>\n\n        <span class=\"n\">db<\/span><span class=\"p\">.<\/span><span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">blog_post<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">db<\/span><span class=\"p\">.<\/span><span class=\"nf\">commit<\/span><span class=\"p\">()<\/span>\n        <span class=\"n\">db<\/span><span class=\"p\">.<\/span><span class=\"nf\">refresh<\/span><span class=\"p\">(<\/span><span class=\"n\">blog_post<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"n\">blog_post<\/span>\n\n    <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">db<\/span><span class=\"p\">.<\/span><span class=\"nf\">rollback<\/span><span class=\"p\">()<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"nc\">HTTPException<\/span><span class=\"p\">(<\/span><span class=\"n\">status_code<\/span><span class=\"o\">=<\/span><span class=\"mi\">500<\/span><span class=\"p\">,<\/span> <span class=\"n\">detail<\/span><span class=\"o\">=<\/span><span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">))<\/span>\n\n<span class=\"nd\">@router.get<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\/blogs<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">response_model<\/span><span class=\"o\">=<\/span><span class=\"n\">BlogListResponse<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">list_blogs<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">skip<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> \n    <span class=\"n\">limit<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">20<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">db<\/span><span class=\"p\">:<\/span> <span class=\"n\">Session<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Depends<\/span><span class=\"p\">(<\/span><span class=\"n\">get_db<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">):<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Get list of all generated blogs<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">total<\/span> <span class=\"o\">=<\/span> <span class=\"n\">db<\/span><span class=\"p\">.<\/span><span class=\"nf\">query<\/span><span class=\"p\">(<\/span><span class=\"n\">BlogPost<\/span><span class=\"p\">).<\/span><span class=\"nf\">count<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">blogs<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span>\n        <span class=\"n\">db<\/span><span class=\"p\">.<\/span><span class=\"nf\">query<\/span><span class=\"p\">(<\/span><span class=\"n\">BlogPost<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">order_by<\/span><span class=\"p\">(<\/span><span class=\"n\">BlogPost<\/span><span class=\"p\">.<\/span><span class=\"n\">created_at<\/span><span class=\"p\">.<\/span><span class=\"nf\">desc<\/span><span class=\"p\">())<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">offset<\/span><span class=\"p\">(<\/span><span class=\"n\">skip<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">limit<\/span><span class=\"p\">(<\/span><span class=\"n\">limit<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">all<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">total<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">total<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">blogs<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">blogs<\/span><span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Key features:<\/strong><\/p>\n\n<ul>\n<li>Automatic request validation via Pydantic<\/li>\n<li>Database transactions with rollback on error<\/li>\n<li>Pagination support for blog listing<\/li>\n<li>Type-safe responses<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  <img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flpiqbv0kd9s64z3opzbv.png\" alt=\"Database Schema\" width=\"800\" height=\"421\">\n<\/h2>\n\n<h2>\n  \n  \n  Frontend Deep Dive\n<\/h2>\n\n<blockquote>\n<p>While I\u2019m primarily backend-focused, I intentionally built the frontend myself to understand how AI latency, UX feedback, and state management interact in real user flows.<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  React Component Architecture\n<\/h3>\n\n<p>I structured the frontend with three main components:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>src\/\n\u251c\u2500\u2500 components\/\n\u2502   \u251c\u2500\u2500 BlogForm.jsx        # Input form\n\u2502   \u251c\u2500\u2500 BlogDisplay.jsx     # Content display\n\u2502   \u2514\u2500\u2500 BlogHistory.jsx     # Blog list\n\u251c\u2500\u2500 services\/\n\u2502   \u2514\u2500\u2500 api.js              # API client\n\u251c\u2500\u2500 utils\/\n\u2502   \u2514\u2500\u2500 helpers.js          # Utility functions\n\u2514\u2500\u2500 App.jsx  \n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  1. BlogForm Component\n<\/h3>\n\n<p>The input form with validation and user-friendly controls:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"c1\">\/\/ src\/components\/BlogForm.jsx<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">React<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">useState<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">react<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Sparkles<\/span><span class=\"p\">,<\/span> <span class=\"nx\">Loader2<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">lucide-react<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">BlogForm<\/span> <span class=\"o\">=<\/span> <span class=\"p\">({<\/span> <span class=\"nx\">onGenerate<\/span><span class=\"p\">,<\/span> <span class=\"nx\">isGenerating<\/span> <span class=\"p\">})<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">formData<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setFormData<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">({<\/span>\n    <span class=\"na\">topic<\/span><span class=\"p\">:<\/span> <span class=\"dl\">''<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">tone<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">professional<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">length<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">medium<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">keywords<\/span><span class=\"p\">:<\/span> <span class=\"dl\">''<\/span><span class=\"p\">,<\/span>\n  <span class=\"p\">});<\/span>\n\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">errors<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setErrors<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">useState<\/span><span class=\"p\">({});<\/span>\n\n  <span class=\"kd\">const<\/span> <span class=\"nx\">toneOptions<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"p\">{<\/span> <span class=\"na\">value<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">professional<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">label<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Professional<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">emoji<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">\ud83d\udcbc<\/span><span class=\"dl\">'<\/span> <span class=\"p\">},<\/span>\n    <span class=\"p\">{<\/span> <span class=\"na\">value<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">casual<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">label<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Casual<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">emoji<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">\ud83d\ude0a<\/span><span class=\"dl\">'<\/span> <span class=\"p\">},<\/span>\n    <span class=\"p\">{<\/span> <span class=\"na\">value<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">technical<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">label<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Technical<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">emoji<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">\ud83d\udd27<\/span><span class=\"dl\">'<\/span> <span class=\"p\">},<\/span>\n    <span class=\"p\">{<\/span> <span class=\"na\">value<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">educational<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">label<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Educational<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">emoji<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">\ud83d\udcda<\/span><span class=\"dl\">'<\/span> <span class=\"p\">},<\/span>\n  <span class=\"p\">];<\/span>\n\n  <span class=\"kd\">const<\/span> <span class=\"nx\">validate<\/span> <span class=\"o\">=<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">newErrors<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{};<\/span>\n    <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"nx\">formData<\/span><span class=\"p\">.<\/span><span class=\"nx\">topic<\/span><span class=\"p\">.<\/span><span class=\"nf\">trim<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">newErrors<\/span><span class=\"p\">.<\/span><span class=\"nx\">topic<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Topic is required<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">formData<\/span><span class=\"p\">.<\/span><span class=\"nx\">topic<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">5<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">newErrors<\/span><span class=\"p\">.<\/span><span class=\"nx\">topic<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Topic must be at least 5 characters<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n    <span class=\"nf\">setErrors<\/span><span class=\"p\">(<\/span><span class=\"nx\">newErrors<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nb\">Object<\/span><span class=\"p\">.<\/span><span class=\"nf\">keys<\/span><span class=\"p\">(<\/span><span class=\"nx\">newErrors<\/span><span class=\"p\">).<\/span><span class=\"nx\">length<\/span> <span class=\"o\">===<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">};<\/span>\n\n  <span class=\"kd\">const<\/span> <span class=\"nx\">handleSubmit<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"nx\">e<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">e<\/span><span class=\"p\">.<\/span><span class=\"nf\">preventDefault<\/span><span class=\"p\">();<\/span>\n    <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nf\">validate<\/span><span class=\"p\">())<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nf\">onGenerate<\/span><span class=\"p\">(<\/span><span class=\"nx\">formData<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">};<\/span>\n\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n\n      <span class=\"nx\">Generate<\/span> <span class=\"nx\">Blog<\/span> <span class=\"nx\">Post<\/span>\n\n\n        <span class=\"p\">{<\/span><span class=\"cm\">\/* Topic Input *\/<\/span><span class=\"p\">}<\/span>\n\n\n            <span class=\"nx\">Blog<\/span> <span class=\"nx\">Topic<\/span> <span class=\"o\">*<\/span>\n\n          <span class=\"p\">&lt;<\/span><span class=\"nt\">input<\/span>\n            <span class=\"na\">type<\/span><span class=\"p\">=<\/span><span class=\"s\">\"text\"<\/span>\n            <span class=\"na\">value<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"nx\">formData<\/span><span class=\"p\">.<\/span><span class=\"nx\">topic<\/span><span class=\"si\">}<\/span>\n            <span class=\"na\">onChange<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"p\">(<\/span><span class=\"nx\">e<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nf\">setFormData<\/span><span class=\"p\">({<\/span>\n              <span class=\"p\">...<\/span><span class=\"nx\">formData<\/span><span class=\"p\">,<\/span> \n              <span class=\"na\">topic<\/span><span class=\"p\">:<\/span> <span class=\"nx\">e<\/span><span class=\"p\">.<\/span><span class=\"nx\">target<\/span><span class=\"p\">.<\/span><span class=\"nx\">value<\/span>\n            <span class=\"p\">})<\/span><span class=\"si\">}<\/span>\n            <span class=\"na\">placeholder<\/span><span class=\"p\">=<\/span><span class=\"s\">\"e.g., The Future of AI\"<\/span>\n            <span class=\"na\">className<\/span><span class=\"p\">=<\/span><span class=\"s\">\"input-field\"<\/span>\n            <span class=\"na\">disabled<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"nx\">isGenerating<\/span><span class=\"si\">}<\/span>\n          <span class=\"p\">\/&gt;<\/span>\n          <span class=\"p\">{<\/span><span class=\"nx\">errors<\/span><span class=\"p\">.<\/span><span class=\"nx\">topic<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"p\">(<\/span>\n            <span class=\"p\">{<\/span><span class=\"nx\">errors<\/span><span class=\"p\">.<\/span><span class=\"nx\">topic<\/span><span class=\"p\">}<\/span>\n          <span class=\"p\">)}<\/span>\n\n\n        <span class=\"p\">{<\/span><span class=\"cm\">\/* Tone Selection *\/<\/span><span class=\"p\">}<\/span>\n\n\n            <span class=\"nx\">Writing<\/span> <span class=\"nx\">Tone<\/span>\n\n\n            <span class=\"p\">{<\/span><span class=\"nx\">toneOptions<\/span><span class=\"p\">.<\/span><span class=\"nf\">map<\/span><span class=\"p\">((<\/span><span class=\"nx\">option<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">(<\/span>\n              <span class=\"p\">&lt;<\/span><span class=\"nt\">button<\/span>\n                <span class=\"na\">key<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"nx\">option<\/span><span class=\"p\">.<\/span><span class=\"nx\">value<\/span><span class=\"si\">}<\/span>\n                <span class=\"na\">type<\/span><span class=\"p\">=<\/span><span class=\"s\">\"button\"<\/span>\n                <span class=\"na\">onClick<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nf\">setFormData<\/span><span class=\"p\">({<\/span>\n                  <span class=\"p\">...<\/span><span class=\"nx\">formData<\/span><span class=\"p\">,<\/span> \n                  <span class=\"na\">tone<\/span><span class=\"p\">:<\/span> <span class=\"nx\">option<\/span><span class=\"p\">.<\/span><span class=\"nx\">value<\/span>\n                <span class=\"p\">})<\/span><span class=\"si\">}<\/span>\n                <span class=\"na\">className<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"s2\">`p-3 rounded-lg border-2 <\/span><span class=\"p\">${<\/span>\n                  <span class=\"nx\">formData<\/span><span class=\"p\">.<\/span><span class=\"nx\">tone<\/span> <span class=\"o\">===<\/span> <span class=\"nx\">option<\/span><span class=\"p\">.<\/span><span class=\"nx\">value<\/span>\n                    <span class=\"p\">?<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">border-primary-500 bg-primary-50<\/span><span class=\"dl\">'<\/span>\n                    <span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">border-gray-200<\/span><span class=\"dl\">'<\/span>\n                <span class=\"p\">}<\/span><span class=\"s2\">`<\/span><span class=\"si\">}<\/span>\n              <span class=\"p\">&gt;<\/span>\n                <span class=\"si\">{<\/span><span class=\"nx\">option<\/span><span class=\"p\">.<\/span><span class=\"nx\">emoji<\/span><span class=\"si\">}<\/span>\n                <span class=\"si\">{<\/span><span class=\"nx\">option<\/span><span class=\"p\">.<\/span><span class=\"nx\">label<\/span><span class=\"si\">}<\/span>\n\n            ))}\n\n\n\n        <span class=\"si\">{<\/span><span class=\"cm\">\/* Submit Button *\/<\/span><span class=\"si\">}<\/span>\n\n          <span class=\"si\">{<\/span><span class=\"nx\">isGenerating<\/span> <span class=\"p\">?<\/span> <span class=\"p\">(<\/span>\n            <span class=\"p\">&lt;&gt;<\/span>\n\n              Generating Content...\n            <span class=\"p\">&lt;\/&gt;<\/span>\n          <span class=\"p\">)<\/span> <span class=\"p\">:<\/span> <span class=\"p\">(<\/span>\n            <span class=\"p\">&lt;&gt;<\/span>\n\n              Generate Blog Post\n            <span class=\"p\">&lt;\/&gt;<\/span>\n          <span class=\"p\">)<\/span><span class=\"si\">}<\/span>\n\n\n\n  );\n};\n\nexport default BlogForm;\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>UI Features:<\/strong><\/p>\n\n<ul>\n<li>Real-time validation<\/li>\n<li>Visual feedback on selection<\/li>\n<li>Loading states during generation<\/li>\n<li>Disabled state management<\/li>\n<li>Clean, modern design with Tailwind<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  2. API Integration\n<\/h3>\n\n<p>Clean API client using Axios:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ src\/services\/api.js<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">axios<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">axios<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">API_BASE_URL<\/span> <span class=\"o\">=<\/span> <span class=\"k\">import<\/span><span class=\"p\">.<\/span><span class=\"nx\">meta<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">VITE_API_URL<\/span> <span class=\"o\">||<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">http:\/\/localhost:8000<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">api<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">axios<\/span><span class=\"p\">.<\/span><span class=\"nf\">create<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">baseURL<\/span><span class=\"p\">:<\/span> <span class=\"s2\">`<\/span><span class=\"p\">${<\/span><span class=\"nx\">API_BASE_URL<\/span><span class=\"p\">}<\/span><span class=\"s2\">\/api\/v1`<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">headers<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"dl\">'<\/span><span class=\"s1\">Content-Type<\/span><span class=\"dl\">'<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">application\/json<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"p\">},<\/span>\n  <span class=\"na\">timeout<\/span><span class=\"p\">:<\/span> <span class=\"mi\">120000<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ 2 minutes for AI generation<\/span>\n<span class=\"p\">});<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">blogAPI<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n  <span class=\"na\">generateBlog<\/span><span class=\"p\">:<\/span> <span class=\"k\">async <\/span><span class=\"p\">(<\/span><span class=\"nx\">data<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">api<\/span><span class=\"p\">.<\/span><span class=\"nf\">post<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/generate<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">data<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">},<\/span>\n\n  <span class=\"na\">getAllBlogs<\/span><span class=\"p\">:<\/span> <span class=\"k\">async <\/span><span class=\"p\">(<\/span><span class=\"nx\">skip<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"nx\">limit<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">20<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">api<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"s2\">`\/blogs?skip=<\/span><span class=\"p\">${<\/span><span class=\"nx\">skip<\/span><span class=\"p\">}<\/span><span class=\"s2\">&amp;limit=<\/span><span class=\"p\">${<\/span><span class=\"nx\">limit<\/span><span class=\"p\">}<\/span><span class=\"s2\">`<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">},<\/span>\n\n  <span class=\"na\">getBlog<\/span><span class=\"p\">:<\/span> <span class=\"k\">async <\/span><span class=\"p\">(<\/span><span class=\"nx\">id<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">api<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"s2\">`\/blogs\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">`<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">},<\/span>\n\n  <span class=\"na\">deleteBlog<\/span><span class=\"p\">:<\/span> <span class=\"k\">async <\/span><span class=\"p\">(<\/span><span class=\"nx\">id<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">api<\/span><span class=\"p\">.<\/span><span class=\"k\">delete<\/span><span class=\"p\">(<\/span><span class=\"s2\">`\/blogs\/<\/span><span class=\"p\">${<\/span><span class=\"nx\">id<\/span><span class=\"p\">}<\/span><span class=\"s2\">`<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">},<\/span>\n<span class=\"p\">};<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why this structure:<\/strong><\/p>\n\n<ul>\n<li>Centralized API configuration<\/li>\n<li>Easy to add interceptors later<\/li>\n<li>Clean function signatures<\/li>\n<li>Environment-based URL configuration<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  3. Utility Functions\n<\/h3>\n\n<p>Helper functions for common tasks:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ src\/utils\/helpers.js<\/span>\n\n<span class=\"c1\">\/\/ Copy to clipboard<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">copyToClipboard<\/span> <span class=\"o\">=<\/span> <span class=\"k\">async <\/span><span class=\"p\">(<\/span><span class=\"nx\">text<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">try<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">await<\/span> <span class=\"nb\">navigator<\/span><span class=\"p\">.<\/span><span class=\"nx\">clipboard<\/span><span class=\"p\">.<\/span><span class=\"nf\">writeText<\/span><span class=\"p\">(<\/span><span class=\"nx\">text<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">return<\/span> <span class=\"kc\">true<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">}<\/span> <span class=\"k\">catch <\/span><span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">Failed to copy:<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">err<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">return<\/span> <span class=\"kc\">false<\/span><span class=\"p\">;<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"c1\">\/\/ Download as file<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">downloadAsFile<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"nx\">content<\/span><span class=\"p\">,<\/span> <span class=\"nx\">filename<\/span><span class=\"p\">,<\/span> <span class=\"nx\">type<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">text\/markdown<\/span><span class=\"dl\">'<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">blob<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nc\">Blob<\/span><span class=\"p\">([<\/span><span class=\"nx\">content<\/span><span class=\"p\">],<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">type<\/span> <span class=\"p\">});<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">url<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">URL<\/span><span class=\"p\">.<\/span><span class=\"nf\">createObjectURL<\/span><span class=\"p\">(<\/span><span class=\"nx\">blob<\/span><span class=\"p\">);<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">link<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nf\">createElement<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">a<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n  <span class=\"nx\">link<\/span><span class=\"p\">.<\/span><span class=\"nx\">href<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">url<\/span><span class=\"p\">;<\/span>\n  <span class=\"nx\">link<\/span><span class=\"p\">.<\/span><span class=\"nx\">download<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">filename<\/span><span class=\"p\">;<\/span>\n  <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nx\">body<\/span><span class=\"p\">.<\/span><span class=\"nf\">appendChild<\/span><span class=\"p\">(<\/span><span class=\"nx\">link<\/span><span class=\"p\">);<\/span>\n  <span class=\"nx\">link<\/span><span class=\"p\">.<\/span><span class=\"nf\">click<\/span><span class=\"p\">();<\/span>\n  <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nx\">body<\/span><span class=\"p\">.<\/span><span class=\"nf\">removeChild<\/span><span class=\"p\">(<\/span><span class=\"nx\">link<\/span><span class=\"p\">);<\/span>\n  <span class=\"nx\">URL<\/span><span class=\"p\">.<\/span><span class=\"nf\">revokeObjectURL<\/span><span class=\"p\">(<\/span><span class=\"nx\">url<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"c1\">\/\/ Get SEO score color<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">getSEOScoreColor<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"nx\">score<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">score<\/span> <span class=\"o\">&gt;=<\/span> <span class=\"mi\">80<\/span><span class=\"p\">)<\/span> <span class=\"k\">return<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">text-green-600 bg-green-100<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n  <span class=\"k\">if <\/span><span class=\"p\">(<\/span><span class=\"nx\">score<\/span> <span class=\"o\">&gt;=<\/span> <span class=\"mi\">60<\/span><span class=\"p\">)<\/span> <span class=\"k\">return<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">text-yellow-600 bg-yellow-100<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n  <span class=\"k\">return<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">text-red-600 bg-red-100<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"c1\">\/\/ Format date<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">formatDate<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"nx\">dateString<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return<\/span> <span class=\"k\">new<\/span> <span class=\"nc\">Date<\/span><span class=\"p\">(<\/span><span class=\"nx\">dateString<\/span><span class=\"p\">).<\/span><span class=\"nf\">toLocaleDateString<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">en-US<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span>\n    <span class=\"na\">year<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">numeric<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">month<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">long<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">day<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">numeric<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">hour<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">2-digit<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">minute<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">2-digit<\/span><span class=\"dl\">'<\/span>\n  <span class=\"p\">});<\/span>\n<span class=\"p\">};<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgdm6h5weup7wybv6tlk8.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgdm6h5weup7wybv6tlk8.png\" alt=\"Blog history\" width=\"800\" height=\"381\"><\/a><\/p>\n\n<h2>\n  \n  \n  Challenges &amp; Solutions\n<\/h2>\n\n<h3>\n  \n  \n  Challenge 1: AI Response Consistency\n<\/h3>\n\n<p><strong>Problem:<\/strong> The AI sometimes generated content in inconsistent formats, making it hard to extract titles and structure.<\/p>\n\n<p><strong>Solution:<\/strong> I built a robust post-processing pipeline:<\/p>\n\n<ul>\n<li>Multiple fallback strategies for title extraction<\/li>\n<li>Regex-based cleaning for artifacts<\/li>\n<li>Format normalization across different outputs<\/li>\n<li>Validation before saving to database\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Fallback chain for title extraction\n<\/span><span class=\"k\">if<\/span> <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"nf\">startswith<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\"># <\/span><span class=\"sh\">'<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">title<\/span> <span class=\"o\">=<\/span> <span class=\"n\">line<\/span><span class=\"p\">.<\/span><span class=\"nf\">replace<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\"># <\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">''<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">elif<\/span> <span class=\"n\">first_line<\/span> <span class=\"ow\">and<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">first_line<\/span><span class=\"p\">)<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">100<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">title<\/span> <span class=\"o\">=<\/span> <span class=\"n\">first_line<\/span>\n<span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">title<\/span> <span class=\"o\">=<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">topic<\/span><span class=\"si\">}<\/span><span class=\"s\">: A Comprehensive Guide<\/span><span class=\"sh\">\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Challenge 2: Long API Response Times\n<\/h3>\n\n<p><strong>Problem:<\/strong> AI generation takes 20-60 seconds, which feels like forever without feedback.<\/p>\n\n<p><strong>Solution:<\/strong> Multiple UX improvements:<\/p>\n\n<ul>\n<li>Clear loading indicators with spinner<\/li>\n<li>Button state changes during generation<\/li>\n<li>Success\/error notifications<\/li>\n<li>Smooth transitions when content appears\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight jsx\"><code><span class=\"p\">{<\/span><span class=\"nx\">isGenerating<\/span> <span class=\"p\">?<\/span> <span class=\"p\">(<\/span>\n  <span class=\"p\">&lt;&gt;<\/span>\n\n    Generating Content...\n  <span class=\"p\">&lt;\/&gt;<\/span>\n<span class=\"p\">)<\/span> <span class=\"p\">:<\/span> <span class=\"p\">(<\/span>\n  <span class=\"p\">&lt;&gt;<\/span>\n\n    Generate Blog Post\n  <span class=\"p\">&lt;\/&gt;<\/span>\n<span class=\"p\">)}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Challenge 3: Model 503 Errors\n<\/h3>\n\n<p><strong>Problem:<\/strong> Hugging Face models go to sleep after inactivity, returning 503 errors on first request.<\/p>\n\n<p><strong>Solution:<\/strong> Implemented retry logic with exponential backoff:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">if<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"n\">status_code<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">503<\/span><span class=\"p\">:<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Model loading... waiting 30 seconds<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">time<\/span><span class=\"p\">.<\/span><span class=\"nf\">sleep<\/span><span class=\"p\">(<\/span><span class=\"mi\">30<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">continue<\/span>  <span class=\"c1\"># Retry\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This handles the warm-up period gracefully.<\/p>\n\n<h3>\n  \n  \n  Challenge 4: SEO Score Fairness\n<\/h3>\n\n<p><strong>Problem:<\/strong> Creating a fair, comprehensive scoring algorithm that doesn't over-penalize or over-reward.<\/p>\n\n<p><strong>Solution:<\/strong> Multi-factor analysis with balanced weights:<\/p>\n\n<ul>\n<li>25 points for word count (most important)<\/li>\n<li>25 points for keyword usage<\/li>\n<li>20 points for structure<\/li>\n<li>15 points for title optimization<\/li>\n<li>15 points for content completeness<\/li>\n<\/ul>\n\n<p>Each factor is independently scored and summed to 100.<\/p>\n\n<h3>\n  \n  \n  Challenge 5: Database Schema Design\n<\/h3>\n\n<p><strong>Problem:<\/strong> How to store flexible keyword lists and maintain efficient queries?<\/p>\n\n<p><strong>Solution:<\/strong><\/p>\n\n<ul>\n<li>Keywords as TEXT field with comma separation<\/li>\n<li>Indexed fields (<code>topic<\/code>, <code>id<\/code>) for fast lookups<\/li>\n<li>Separate <code>title<\/code> and <code>content<\/code> fields for granular access<\/li>\n<li>Timestamps for sorting and filtering<\/li>\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Current Status &amp; Demo\n<\/h2>\n\n<p>Here's what we have working right now:<\/p>\n\n<p><strong>Backend:<\/strong><\/p>\n\n<ul>\n<li>FastAPI server running smoothly<\/li>\n<li>Database models and migrations<\/li>\n<li>AI integration with Hugging Face<\/li>\n<li>SEO scoring algorithm<\/li>\n<li>Complete CRUD API<\/li>\n<\/ul>\n\n<p><strong>Frontend:<\/strong><\/p>\n\n<ul>\n<li>Beautiful, responsive UI<\/li>\n<li>Blog generation form<\/li>\n<li>Real-time content display<\/li>\n<li>Blog history management<\/li>\n<li>Copy and download features<\/li>\n<\/ul>\n\n<p><strong>Features:<\/strong><\/p>\n\n<ul>\n<li>Multiple writing tones<\/li>\n<li>Flexible content length<\/li>\n<li>Keyword optimization<\/li>\n<li>SEO scoring<\/li>\n<li>Content persistence<\/li>\n<\/ul>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxn1rlx40d8ylyeme6535.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxn1rlx40d8ylyeme6535.png\" alt=\"Demo image 1\" width=\"800\" height=\"376\"><\/a><\/p>\n\n<p><strong>Try it yourself:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Clone the repo<\/span>\ngit clone https:\/\/github.com\/yourusername\/ai-blog-generator\n\n<span class=\"c\"># Backend<\/span>\n<span class=\"nb\">cd <\/span>backend\npython <span class=\"nt\">-m<\/span> venv venv\n<span class=\"nb\">source <\/span>venv\/bin\/activate\npip <span class=\"nb\">install<\/span> <span class=\"nt\">-r<\/span> requirements.txt\nuvicorn app.main:app <span class=\"nt\">--reload<\/span>\n\n<span class=\"c\"># Frontend<\/span>\n<span class=\"nb\">cd <\/span>frontend\nnpm <span class=\"nb\">install\n<\/span>npm run dev\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frr5e2agbue2mztv3xsx0.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frr5e2agbue2mztv3xsx0.png\" alt=\"Complete UI\" width=\"800\" height=\"615\"><\/a><\/p>\n\n<h2>\n  \n  \n  What I Learned\n<\/h2>\n\n<h3>\n  \n  \n  Technical Lessons\n<\/h3>\n\n<ol>\n<li>\n<strong>Prompt Engineering Matters<\/strong>: The quality of AI output is 80% about the prompt. I spent hours refining the structure.<\/li>\n<li>\n<strong>Post-Processing is Essential<\/strong>: Never trust raw AI output - always clean, validate, and structure it.<\/li>\n<li>\n<strong>UX During Long Operations<\/strong>: Loading states, progress indicators, and clear feedback are crucial for good UX.<\/li>\n<li>\n<strong>Type Safety Saves Time<\/strong>: Pydantic validation caught countless bugs before they reached production.<\/li>\n<li>\n<strong>Database Indexing<\/strong>: Proper indexing on topic and timestamps made queries 10x faster.<\/li>\n<\/ol>\n\n<h3>\n  \n  \n  Soft Skills\n<\/h3>\n\n<ol>\n<li>\n<strong>Breaking Down Complexity<\/strong>: Dividing the project into services made it manageable.<\/li>\n<li>\n<strong>Iterative Development<\/strong>: Started with basic generation, then added SEO, then optimized prompts.<\/li>\n<li>\n<strong>User-First Design<\/strong>: Always thinking \"how would I want this to work?\" improved the UX significantly.<\/li>\n<\/ol>\n\n<h2>\n  \n  \n  \ud83d\ude80 What's Next (Part 2)\n<\/h2>\n\n<p>In the next post, I'll cover:<\/p>\n\n<ol>\n<li>Deploying Backend to Railway<\/li>\n<\/ol>\n\n<ul>\n<li>Setting up PostgreSQL<\/li>\n<li>Environment variables<\/li>\n<li>Handling production errors<\/li>\n<li><p>Deploying Frontend to Vercel<\/p><\/li>\n<li><p>Build optimization<\/p><\/li>\n<li><p>Environment configuration<\/p><\/li>\n<li><p>Custom domain setup<\/p><\/li>\n<li><p>Production Optimizations<\/p><\/li>\n<li><p>Caching strategies<\/p><\/li>\n<li><p>Rate limiting<\/p><\/li>\n<li><p>Monitoring and logging<\/p><\/li>\n<li><p>Future Enhancements<\/p><\/li>\n<li><p>Image generation for blog posts<\/p><\/li>\n<li><p>Multi-language support<\/p><\/li>\n<li><p>Content scheduling<\/p><\/li>\n<li><p>Analytics dashboard<\/p><\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Key Takeaways\n<\/h3>\n\n<p>If you're building an AI-powered application, here are my top recommendations:<\/p>\n\n<ol>\n<li>\n<strong>Start Simple<\/strong>: Get basic generation working before adding complexity<\/li>\n<li>\n<strong>Invest in Prompt Engineering<\/strong>: It's the most important factor for output quality<\/li>\n<li>\n<strong>Build Robust Error Handling<\/strong>: AI APIs fail - plan for it<\/li>\n<li>\n<strong>Focus on UX<\/strong>: Long wait times need great feedback<\/li>\n<li>\n<strong>Test with Real Users<\/strong>: Get feedback early and iterate<\/li>\n<\/ol>\n\n<p>### Resources &amp; Links<\/p>\n\n<ul>\n<li><a href=\"https:\/\/github.com\/Lymah123\/ai-blog-generator\" rel=\"noopener noreferrer\">GitHub Repository<\/a><\/li>\n<li>Live Demo: Coming in Part 2!<\/li>\n<li><a href=\"https:\/\/fastapi.tiangolo.com\/\" rel=\"noopener noreferrer\">FastAPI Docs<\/a><\/li>\n<li><a href=\"https:\/\/huggingface.co\/\" rel=\"noopener noreferrer\">Hugging Face<\/a><\/li>\n<li><a href=\"https:\/\/tailwindcss.com\/\" rel=\"noopener noreferrer\">Tailwind CSS<\/a><\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Let's Connect\n<\/h3>\n\n<p>Building this project was an incredible learning experience. I'd love to hear your thoughts:<\/p>\n\n<ul>\n<li>What features would you add?<\/li>\n<li>What challenges have you faced with AI integration?<\/li>\n<li>Any questions about the implementation?<\/li>\n<\/ul>\n\n<p>Drop a comment below or connect with me:<\/p>\n\n<ul>\n<li><a href=\"https:\/\/github.com\/Lymah123\" rel=\"noopener noreferrer\">GitHub<\/a><\/li>\n<li><a href=\"https:\/\/twitter.com\/CodesLymah\" rel=\"noopener noreferrer\">X<\/a><\/li>\n<li><a href=\"https:\/\/www.linkedin.com\/in\/harlimat-odunola-2ab261235\" rel=\"noopener noreferrer\">LinkedIn<\/a><\/li>\n<\/ul>\n\n<p>\ud83d\udce2 ### Stay Tuned for Part 2!<br>\nNext up: <strong>Deployment to Production<\/strong><br>\nI'll walk through:<\/p>\n\n<ul>\n<li>Railway deployment for backend<\/li>\n<li>Vercel deployment for frontend<\/li>\n<li>Domain setup and SSL<\/li>\n<li>Production monitoring<\/li>\n<li>Performance optimization<\/li>\n<\/ul>\n\n<p><em>Make sure to follow me to get notified when Part 2 drops!<\/em><\/p>\n\n<p>Thanks for reading! If you found this helpful, please give it a \u2764\ufe0f and share with others who might benefit from it.<\/p>\n\n","category":["python","ai","react","backend"]},{"title":"Hacktoberfest 2025 Reflection: Three Years, Three Lessons, One Evolution","pubDate":"Thu, 30 Oct 2025 01:40:36 +0000","link":"https:\/\/dev.to\/lymah\/hacktoberfest-2025-reflection-three-years-three-lessons-one-evolution-29ba","guid":"https:\/\/dev.to\/lymah\/hacktoberfest-2025-reflection-three-years-three-lessons-one-evolution-29ba","description":"<p><em>This is a submission for the <a href=\"https:\/\/dev.to\/challenges\/hacktoberfest2025\">2025 Hacktoberfest Writing Challenge<\/a>: Open Source Reflections<\/em><\/p>\n\n<h2>\n  \n  \n  The Three-Year Journey\n<\/h2>\n\n<p>This was my third Hacktoberfest, and each year taught me something different about what open source really means.<br>\n<strong>Hacktoberfest 2023<\/strong>: My first year\u2014excited, overwhelmed, hunting for \"good first issues\"<br>\n<strong>Hacktoberfest 2024<\/strong>: More confident, making targeted contributions, starting to understand project ecosystems<br>\n<strong>Hacktoberfest 2025<\/strong>: Finally clicked\u2014focused on impact over activity, documentation as infrastructure, solving problems at scale<\/p>\n\n<h3>\n  \n  \n  Hacktoberfest 2025: What I Built\n<\/h3>\n\n<p>This year, I contributed to <a href=\"https:\/\/github.com\/block\/goose\" rel=\"noopener noreferrer\">goose<\/a> (Block's open source AI developer tool) by creating comprehensive documentation addressing enterprise adoption gaps.<\/p>\n\n<h4>\n  \n  \n  My 2025 Contributions\n<\/h4>\n\n<p>Four-part documentation series (40,000+ words):<\/p>\n\n<ol>\n<li>\n<a href=\"https:\/\/dev.to\/lymah\/getting-started-with-goose-on-windows-30bh\">Getting Started with goose on Windows<\/a> - Platform-specific guide with troubleshooting<\/li>\n<li>\n<a href=\"https:\/\/dev.to\/lymah\/best-practices-for-prompt-engineering-with-goose-3m6h\">Best Practices for Prompt Engineering<\/a> - 6 techniques with 50+ production examples<\/li>\n<li>\n<a href=\"https:\/\/dev.to\/lymah\/deep-dive-into-gooses-extension-system-and-model-context-protocol-mcp-3ehl\">Deep Dive into MCP Extensions<\/a> - Complete technical reference with production patterns<\/li>\n<li>\n<a href=\"https:\/\/dev.to\/lymah\/configuring-goose-for-team-environments-and-shared-workflows-5ehn\">Team Configuration Guide<\/a> - Enterprise deployment frameworks<\/li>\n<li>\n<a href=\"https:\/\/github.com\/block\/goose\/pull\/5371\" rel=\"noopener noreferrer\">Docs: add Linux and Windows paths to uninstall section<\/a> - Add Linux and Windows paths to uninstall section<\/li>\n<\/ol>\n\n<ul>\n<li>Updates the 'Uninstall Goose or Remove Cached Data' section to include<\/li>\n<li>platform-specific paths for Linux and Windows alongside existing macOS paths.<\/li>\n<\/ul>\n\n<p>Plus production-ready tools: setup scripts, cost tracking, configuration validation, security frameworks.<\/p>\n\n<h3>\n  \n  \n  The Evolution: What Changed Year Over Year\n<\/h3>\n\n<h4>\n  \n  \n  2023: Hunting for Issues\n<\/h4>\n\n<ul>\n<li>\n<strong>Focus<\/strong>: Finding \"good first issues\" I could solve<\/li>\n<li>\n<strong>Mindset<\/strong>: \"What can I contribute?\"<\/li>\n<li>\n<strong>Success metric<\/strong>: Number of merged PRs<\/li>\n<li>\n<strong>Learning<\/strong>: How to make a pull request, work with Git, follow contribution guidelines<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  2024: Understanding Projects\n<\/h4>\n\n<ul>\n<li>\n<strong>Focus<\/strong>: Contributing to projects I actually used<\/li>\n<li>\n<strong>Mindset<\/strong>: \"How can I help this project?\"<\/li>\n<li>\n<strong>Success metric<\/strong>: Quality of contributions<\/li>\n<li>\n<strong>Learning<\/strong>: How projects work, what maintainers need, how to write better code<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  2025: Solving Real Problems\n<\/h4>\n\n<ul>\n<li>\n<strong>Focus<\/strong>: Identifying gaps and filling them completely<\/li>\n<li>\n<strong>Mindset<\/strong>: \"What's stopping adoption of this tool?\"<\/li>\n<li>\n<strong>Success metric<\/strong>: Measurable impact on users<\/li>\n<li>\n<strong>Learning<\/strong>: Documentation IS infrastructure, production matters more than demos<\/li>\n<\/ul>\n\n<p><strong>The Pattern<\/strong>: Each year, my contributions got fewer but more impactful. 2023 was many small PRs. 2024 was fewer, better PRs. 2025 was comprehensive solutions to complex problems.<\/p>\n\n<h3>\n  \n  \n  What I Learned This Year\n<\/h3>\n\n<h4>\n  \n  \n  1. Documentation is Infrastructure (Not Afterthought)\n<\/h4>\n\n<p>In 2023-2024, I saw documentation as \"nice to have.\" In 2025, I realized it's infrastructure\u2014the foundation that enables adoption.<br>\ngoose works great for maintainers but was hard for teams to deploy at scale. My documentation bridges that gap: configuration management, security, cost tracking, governance. Without these pieces, enterprises can't adopt AI tools no matter how good they are.<br>\n<strong>Lesson<\/strong>: The best contributions remove barriers. Code that works but can't be deployed is just potential.<\/p>\n\n<h4>\n  \n  \n  2. The Meta-Loop: Using Tools to Improve Themselves\n<\/h4>\n\n<p>This year's unique insight: I used goose to contribute to goose.<\/p>\n\n<ul>\n<li>Used goose to analyze documentation gaps<\/li>\n<li>Used goose to research common problems<\/li>\n<li>Used goose to draft content and iterate<\/li>\n<li>Used goose to create production scripts<\/li>\n<li>Used goose to refine technical accuracy\n<strong>This taught me:<\/strong> the best way to understand a tool is to use it to improve itself. You can't fake this depth of understanding\u2014it comes from actually solving problems with the tool.\n<strong>Lesson<\/strong>: Use what you're contributing to. Real usage reveals what docs miss.<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  4. Community Amplifies Everything\n<\/h4>\n\n<p>In 2023, I contributed and moved on. In 2024, I started engaging with maintainers. In 2025, I realized community feedback makes contributions better:<\/p>\n\n<ul>\n<li>Comments revealed what I'd missed<\/li>\n<li>Users shared their workarounds<\/li>\n<li>Platform teams asked about patterns<\/li>\n<li>Other contributors built on my work<\/li>\n<\/ul>\n\n<p><strong>Lesson:<\/strong> Open source isn't a solo activity. The community improves what you create<\/p>\n\n<h3>\n  \n  \n  How My Perspective Changed\n<\/h3>\n\n<h4>\n  \n  \n  What Open Source Meant to Me in 2023:\n<\/h4>\n\n<p>Contributing code to repositories, fixing bugs, adding features<\/p>\n\n<h4>\n  \n  \n  What Open Source Means to Me in 2025:\n<\/h4>\n\n<p>Building infrastructure that democratizes access\u2014to tools, knowledge, and best practices<\/p>\n\n<p><strong>The shift<\/strong>: from contributing to projects to contributing to ecosystems.<br>\ngoose isn't just a tool\u2014it's part of an ecosystem:<\/p>\n\n<ul>\n<li>MCP is an open standard (works across Claude, Cursor, etc.)<\/li>\n<li>Extensions are composable (build once, use everywhere)<\/li>\n<li>Documentation helps everyone (users, contributors, enterprises)<\/li>\n<li>Improvements compound (each contribution builds on others)<\/li>\n<\/ul>\n\n<p>When I create documentation, I'm not just explaining features\u2014I'm:<\/p>\n\n<ul>\n<li>Lowering barriers for Windows developers<\/li>\n<li>Helping small teams access enterprise-grade AI<\/li>\n<li>Giving companies frameworks to adopt tools safely<\/li>\n<li>Contributing to collective knowledge<\/li>\n<\/ul>\n\n<p><strong>The realization<\/strong>: Open source's power isn't free code\u2014it's that improvements compound. My docs help teams deploy faster, they discover better patterns, they share them, someone improves on that, everyone benefits.<\/p>\n\n<h4>\n  \n  \n  Three Years of Lessons\n<\/h4>\n\n<p><strong>Year 1 (2023): The Mechanics<\/strong><\/p>\n\n<ul>\n<li>How to find projects<\/li>\n<li>How to make PRs<\/li>\n<li>How to follow contribution guidelines<\/li>\n<li>How Git\/GitHub work<\/li>\n<li>How to communicate with maintainers<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Year 2 (2024): The Context\n<\/h4>\n\n<ul>\n<li>Why projects make certain decisions<\/li>\n<li>What maintainers actually need<\/li>\n<li>How to write quality contributions<\/li>\n<li>How projects are structured<\/li>\n<li>How to think about tradeoffs<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Year 3 (2025): The Impact\n<\/h4>\n\n<ul>\n<li>What stops tool adoption<\/li>\n<li>How to solve problems at scale<\/li>\n<li>What production means vs demo<\/li>\n<li>How documentation enables adoption<\/li>\n<li>How contributions compound<\/li>\n<\/ul>\n\n<p><strong>The Lesson<\/strong>: Open source is a journey from mechanics \u2192 context \u2192 impact. Early years teach you HOW to contribute. Later years teach you WHERE and WHY to contribute<\/p>\n\n<h4>\n  \n  \n  Advice for Different Stages\n<\/h4>\n\n<p><strong>For First-Time Participants (Where I Was in 2023):<\/strong><\/p>\n\n<ol>\n<li>Start with Tools You Use - Don't just hunt \"good first issues.\" Contribute to tools you actually use\u2014you'll understand the problems better.<\/li>\n<li>Read the Contribution Guidelines - Every project has them. Following them shows respect and gets your PR merged faster.<\/li>\n<li>Start Small, Ship Often - Fix typos, improve docs, add tests. Don't aim for perfect\u2014aim for shipped.<\/li>\n<li>Learn Git Properly - It's worth the time investment. You'll use it everywhere.<\/li>\n<li>Engage Respectfully - Maintainers are volunteers. Be patient, be kind, be helpful.<\/li>\n<\/ol>\n\n<p><strong>For Second-Year Participants (Where I Was in 2024):<\/strong><\/p>\n\n<ol>\n<li>Go Deeper, Not Wider - Instead of 20 small PRs, make 5 substantial ones. Quality over quantity.<\/li>\n<li>Understand the Project - Read the architecture docs. Understand why it works that way. Your contributions will be better.<\/li>\n<li>Fix Related Issues Together - If you find one bug, look for related bugs. Fix them together in one PR.<\/li>\n<li>Ask \"Why?\" - When maintainers suggest changes, ask why. Learn their reasoning. It makes you better.<\/li>\n<li>Think About Maintainability - Your code will be maintained by others. Make it clear, well-tested, document\ned.<\/li>\n<\/ol>\n\n<p><strong>For Experienced Participants (Where I Am in 2025):<\/strong><\/p>\n\n<ol>\n<li>Find the Adoption Gaps - Look for what stops people from using great tools. That's where impact lives.<\/li>\n<li>Think in Complete Solutions - Don't just answer one question\u2014create comprehensive resources that solve all related problems.<\/li>\n<li>Use the Tool to Improve the Tool - If contributing to AI tools, use AI. If contributing to testing frameworks, test them. Meta-usage gives deep understanding.<\/li>\n<li>Focus on Production Patterns - Demos are everywhere. Production-ready solutions are rare and valuable.<\/li>\n<li>Measure Impact, Not Activity - Did your contribution actually help people? That's the metric that matters.<\/li>\n<li>Build for Scale - Individual use is one thing. 50 developers is another. Address the latter.<\/li>\n<li>Engage Long-Term - Don't disappear after October. Answer questions, update docs, help others.<\/li>\n<\/ol>\n\n<h3>\n  \n  \n  What This Year Taught Me About Open Source\n<\/h3>\n\n<p>Open source is about compound improvements.<br>\nWhen I document how to deploy goose:<\/p>\n\n<ul>\n<li>Teams deploy successfully<\/li>\n<li>They discover better patterns<\/li>\n<li>They share those patterns<\/li>\n<li>Someone improves on them<\/li>\n<li>Documentation gets updated<\/li>\n<li>The next team starts higher<\/li>\n<li>The ecosystem improves<\/li>\n<\/ul>\n\n<p>This compounding is why open source is powerful. We're not building in isolation\u2014we're building on each other's work. Each contribution makes the next easier.<\/p>\n\n<blockquote>\n<p>The best contributions make the next contribution easier.<\/p>\n<\/blockquote>\n\n<p>That's what I focused on in 2025: creating infrastructure that others can build on. Not just solving my problem, but creating frameworks that help thousands of teams solve similar problems.<\/p>\n\n<h4>\n  \n  \n  The Three-Year Arc\n<\/h4>\n\n<p><strong>2023:<\/strong> Learning the mechanics of open source<br>\n<strong>2024:<\/strong> Understanding how projects work<br>\n<strong>2025:<\/strong> Creating infrastructure for adoption<br>\n<strong>2026 (Goal)<\/strong>: Contributing code that solves the problems I documented<br>\n<strong>The progression is clear<\/strong>: u_ser \u2192 documentation contributor \u2192 code contributor \u2192 maintainer._ <br>\nEach step builds on the previous. Each year, I understand more about what makes open source work.<\/p>\n\n<h4>\n  \n  \n  Looking Forward\n<\/h4>\n\n<p>Three Hacktoberfests taught me that the best path is:<\/p>\n\n<p>\u2705 Use the tool (learn deeply)<br>\n\u2705 Document the tool (help others)<br>\n\u2192 Build the tool (next step)<br>\n\u2192 Maintain the tool (future goal)<\/p>\n\n<p>This year showed me I want to go deeper with goose. I've documented the gaps\u2014now I want to fix them at the source. Move from explaining problems to solving them in code.<br>\nThat's the beautiful thing about open source\u2014there's always a next level, always a way to contribute more, always an opportunity to increase impact.<\/p>\n\n<h4>\n  \n  \n  Final Reflection\n<\/h4>\n\n<p><strong>If 2023 Me Could See 2025 Me:<\/strong><br>\n2023 Me: \"Look how many PRs I made!\"<br>\n2025 Me: \"Look how many teams I helped.\"<br>\nThe shift from quantity to quality, from activity to impact, from contributions to infrastructure\u2014that's the three-year journey.<\/p>\n\n<p><strong>What I'd Tell 2023 Me:<\/strong><br>\n\"Stop hunting for issues. Find a tool you love, use it deeply, understand where it struggles, then fix that. One impactful contribution beats ten surface-level PRs. Quality compounds. Activity doesn't.\"<\/p>\n\n<p><strong>What Excites Me About 2026:<\/strong><br>\nMoving from documenting problems to solving them in code. Contributing to goose's codebase. Building features that make enterprise adoption easier. Helping the next wave of contributors.<\/p>\n\n\n\n\n<p><strong>Three years in, one lesson clear: Open source isn't about heroic individual contributions. It's about collective progress. It's about building infrastructure others can stand on. It's about making the next contribution easier.<br>\nThank you to every maintainer, every contributor, every person who answered my questions, and every team that made open source better. Here's to year four. \ud83d\ude80<\/strong><\/p>\n\n","category":["devchallenge","hacktoberfest","opensource"]},{"title":"Building Effective Prompts and Workflows for Code Review with goose","pubDate":"Wed, 29 Oct 2025 15:49:58 +0000","link":"https:\/\/dev.to\/lymah\/building-effective-prompts-and-workflows-for-code-review-with-goose-51m1","guid":"https:\/\/dev.to\/lymah\/building-effective-prompts-and-workflows-for-code-review-with-goose-51m1","description":"<p>Code review is one of the most valuable and time-consuming activities in software development. Done well, it catches bugs, spreads knowledge, and maintains code quality. Done poorly, it becomes a bottleneck that slows delivery and frustrates teams. Enter <a href=\"https:\/\/github.com\/block\/goose\" rel=\"noopener noreferrer\">goose<\/a>, Block's open source AI agent that can transform how you approach code review.<\/p>\n\n<p>This guide will show you how to build effective prompts and workflows that leverage goose to enhance your code review process while maintaining the human judgment that makes reviews valuable.<\/p>\n\n<blockquote>\n<p><strong>New to goose prompting?<\/strong> Check out <a href=\"https:\/\/dev.to\/lymah\/lymah\/best-practices-for-prompt-engineering-with-goose-3m6h\">Best Practices for Prompt Engineering with goose<\/a> to master the fundamentals before diving into these code review-specific techniques.<\/p>\n<\/blockquote>\n\n<h2>\n  \n  \n  Why Use goose for Code Review?\n<\/h2>\n\n<p>Before diving into prompts and workflows, let's understand what makes goose uniquely suited for code review:<\/p>\n\n<p><strong>Local Execution<\/strong>: goose runs on your machine, giving you complete control over your code and keeping sensitive intellectual property secure. Unlike cloud-based tools, there's no data leaving your environment.<\/p>\n\n<p><strong>Model Flexibility<\/strong>: You can configure goose to use any LLM\u2014from GPT-4 to Claude to local models\u2014allowing you to balance cost, performance, and privacy based on your needs.<\/p>\n\n<p><strong>Autonomous Action<\/strong>: goose doesn't just suggest changes; it can read files, run tests, check dependencies, and even make modifications autonomously when instructed. This means it can verify its own suggestions before presenting them.<\/p>\n\n<p><strong>Extensibility<\/strong>: Through the Model Context Protocol (MCP), Goose integrates with your existing tools, including GitHub, GitLab, Jira, and Slack, allowing it to fit seamlessly into your current workflow.<\/p>\n\n<h3>\n  \n  \n  Understanding goose's Code Review Capabilities\n<\/h3>\n\n<p>goose excels at several code review tasks:<\/p>\n\n<ul>\n<li>\n<strong>Pattern Recognition<\/strong>: Identifying common anti-patterns, code smells, and violations of established conventions<\/li>\n<li>\n<strong>Context Analysis<\/strong>: Understanding the broader codebase to suggest improvements that align with existing architecture<\/li>\n<li>\n<strong>Test Verification<\/strong>: Running tests to confirm proposed changes don't break functionality<\/li>\n<li>\n<strong>Documentation Gaps<\/strong>: Flagging missing or outdated documentation<\/li>\n<li>\n<strong>Security Scanning<\/strong>: Identifying potential security vulnerabilities and suggesting fixes<\/li>\n<li>\n<strong>Performance Analysis<\/strong>: Spotting inefficient code patterns that could impact performance<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Code Review-Specific Prompting Patterns\n<\/h3>\n\n<p>While the <a href=\"https:\/\/dev.to\/lymah\/best-practices-for-prompt-engineering-with-goose-3m6h\">general prompting guide<\/a> covers foundational techniques, code review requires specialized patterns.<\/p>\n\n<h4>\n  \n  \n  The Severity-Based Review Pattern\n<\/h4>\n\n<p>Structure your reviews by severity level to ensure critical issues get immediate attention:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Review [files] using these severity levels:\n\n\ud83d\udd34 CRITICAL (block merge):\n- Security vulnerabilities (injection, auth bypasses)\n- Data loss or corruption risks\n- Breaking changes to public APIs\n- Unhandled error paths that could crash production\n\n\ud83d\udfe1 HIGH (must fix before merge):\n- Performance issues (N+1 queries, memory leaks)\n- Missing error handling for recoverable errors\n- Test coverage below 80% for new code\n- SOLID principle violations\n\n\ud83d\udfe2 MEDIUM (should address):\n- Code readability issues\n- Inconsistent naming or style\n- Missing documentation\n- Potential edge cases\n\n\u26aa LOW (nice to have):\n- Minor refactoring opportunities\n- Additional test coverage\n- Style nitpicks\n\nFor each issue found:\n1. Severity level with emoji\n2. Specific line numbers\n3. Explanation of impact\n4. Concrete fix with code example\n5. If CRITICAL or HIGH: implement the fix and verify with tests\n\nFormat as a GitHub\/GitLab comment I can paste directly.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  The Autonomous Fix-and-Verify Pattern\n<\/h4>\n\n<p>Let goose prove its suggestions work before you review them:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Review [file] for security issues and:\n\n1. Identify each vulnerability\n2. Assess the risk (critical\/high\/medium\/low)\n3. For CRITICAL and HIGH risks:\n   a. Create a fix branch\n   b. Implement the solution\n   c. Run the test suite\n   d. Run security scan tools if available\n   e. ONLY present fixes that pass all checks\n4. For MEDIUM\/LOW:\n   a. Suggest the fix with explanation\n   b. Don't implement unless I ask\n\nPresent findings as:\n- Issue: [description]\n- Impact: [what could happen]\n- Fix: [code that passed tests]\n- Test Results: [proof it works]\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why this works<\/strong>: You get pre-validated solutions instead of untested suggestions, saving review cycles.<\/p>\n\n<h4>\n  \n  \n  The Architectural Context Pattern\n<\/h4>\n\n<p>Help goose understand your codebase's design principles:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Review [new-feature-files] for architectural consistency:\n\nOUR ARCHITECTURE:\n1. Layered Architecture (strict):\n   - Routes \u2192 Controllers \u2192 Services \u2192 Models\n   - NO business logic in controllers\n   - NO direct model access from controllers\n\n2. Dependency Rules:\n   - Services can depend on models and other services\n   - Controllers depend only on services\n   - Models have no dependencies on upper layers\n\n3. Error Handling Standard:\n   - Services throw domain-specific errors\n   - Controllers catch and translate to HTTP responses\n   - All errors logged with context\n\n4. File Organization:\n   - Group by feature, not by layer\n   - Each feature is a subdirectory with all its layers\n\nREVIEW CHECKLIST:\n\u2713 Does this follow our layering rules?\n\u2713 Are dependencies flowing in the right direction?\n\u2713 Is business logic in the correct layer?\n\u2713 Does error handling follow our pattern?\n\u2713 Is the file organization consistent?\n\nFor violations:\n- Quote the problematic code\n- Explain which principle it violates\n- Show how to fix it following our patterns\n- Reference similar code in the codebase that does it correctly\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  The Comparative Review Pattern\n<\/h4>\n\n<p>When evaluating different approaches in a PR:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>I'm reviewing two proposed implementations for [feature]:\n\nAPPROACH A (Current PR):\n[Link or description]\n\nAPPROACH B (Alternative suggested):\n[Link or description]\n\nCompare them on these dimensions:\n\n1. **Correctness** (do both work?)\n   - Test both implementations\n   - Check edge cases\n   - Verify error handling\n\n2. **Performance** (which is faster?)\n   - Analyze time complexity\n   - Consider space complexity\n   - Note any potential bottlenecks\n\n3. **Maintainability** (which is clearer?)\n   - Rate code readability (1-10)\n   - Assess how easy to modify\n   - Check for code smells\n\n4. **Testability** (which is easier to test?)\n   - Mock complexity\n   - Test coverage potential\n   - Integration test needs\n\n5. **Consistency** (which fits our codebase better?)\n   - Pattern alignment\n   - Style consistency\n   - Dependency choices\n\n6. **Future-proofing** (which handles growth better?)\n   - Extensibility\n   - Breaking change risk\n   - Migration path if needed\n\nProvide:\n- Side-by-side comparison table\n- Recommendation with confidence level (%)\n- Reasoning for recommendation\n- If close call, trade-offs to consider\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Complete Code Review Workflows\n<\/h3>\n\n<h4>\n  \n  \n  Workflow 1: Pre-Commit Self-Review\n<\/h4>\n\n<p>Catch issues before creating a PR:<br>\n<strong>Script<\/strong>: <code>scripts\/goose-precommit.sh<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\">#!\/bin\/bash<\/span>\n\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\ud83e\udda2 Running goose pre-commit review...\"<\/span>\n\n<span class=\"nv\">CHANGED_FILES<\/span><span class=\"o\">=<\/span><span class=\"si\">$(<\/span>git diff <span class=\"nt\">--cached<\/span> <span class=\"nt\">--name-only<\/span> <span class=\"nt\">--diff-filter<\/span><span class=\"o\">=<\/span>ACM<span class=\"si\">)<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"o\">[<\/span> <span class=\"nt\">-z<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$CHANGED_FILES<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">]<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"No staged files to review\"<\/span>\n    <span class=\"nb\">exit <\/span>0\n<span class=\"k\">fi\n\n<\/span>goose session start <span class=\"s2\">\"precommit-<\/span><span class=\"si\">$(<\/span><span class=\"nb\">date<\/span> +%s<span class=\"si\">)<\/span><span class=\"s2\">\"<\/span>\n\n<span class=\"nb\">cat<\/span> <span class=\"o\">&lt;&lt;<\/span><span class=\"no\">EOF<\/span><span class=\"sh\"> | goose prompt\nPre-commit review of staged files:\n\n<\/span><span class=\"si\">$(<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$CHANGED_FILES<\/span><span class=\"s2\">\"<\/span> | <span class=\"nb\">sed<\/span> <span class=\"s1\">'s\/^\/- \/'<\/span><span class=\"si\">)<\/span><span class=\"sh\">\n\nQUICK CHECKS (auto-fix if possible):\n1. Run linter and fix violations\n2. Remove console.log\/debugger statements\n3. Remove commented-out code blocks\n4. Check for TODO\/FIXME comments (list them)\n5. Verify no secrets or API keys\n\nQUALITY CHECKS (report only):\n1. New functions have tests?\n2. Complex logic has comments?\n3. Error handling present?\n4. Type safety (TypeScript types\/JSDoc)?\n\nFor auto-fixed issues:\n- Show what you fixed\n- Make the changes\n- Confirm they're ready to commit\n\nFor quality issues:\n- Create a checklist of concerns\n- Let me decide whether to fix now or later\n\nSafe to commit? YES\/NO with reasoning.\n<\/span><span class=\"no\">EOF\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Integration with Git<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code># .git\/hooks\/pre-commit\n#!\/bin\/bash\n.\/scripts\/goose-precommit.sh\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Workflow 2: Automated PR Initial Review\n<\/h4>\n\n<p>Add this as a GitHub Action to review PRs automatically:<br>\n<code>.github\/workflows\/goose-review.yml<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">goose PR Review<\/span>\n\n<span class=\"na\">on<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">pull_request<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">types<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"nv\">opened<\/span><span class=\"pi\">,<\/span> <span class=\"nv\">synchronize<\/span><span class=\"pi\">]<\/span>\n\n<span class=\"na\">jobs<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">review<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">runs-on<\/span><span class=\"pi\">:<\/span> <span class=\"s\">ubuntu-latest<\/span>\n    <span class=\"na\">steps<\/span><span class=\"pi\">:<\/span>\n      <span class=\"pi\">-<\/span> <span class=\"na\">uses<\/span><span class=\"pi\">:<\/span> <span class=\"s\">actions\/checkout@v3<\/span>\n        <span class=\"na\">with<\/span><span class=\"pi\">:<\/span>\n          <span class=\"na\">fetch-depth<\/span><span class=\"pi\">:<\/span> <span class=\"m\">0<\/span>\n\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">Get changed files<\/span>\n        <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s\">changes<\/span>\n        <span class=\"na\">run<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">|<\/span>\n          <span class=\"s\">echo \"files=$(git diff --name-only origin\/${{ github.base_ref }}...HEAD | tr '\\n' ' ')\" &gt;&gt; $GITHUB_OUTPUT<\/span>\n\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">Install goose<\/span>\n        <span class=\"na\">run<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">|<\/span>\n          <span class=\"s\">curl -sSL https:\/\/block.github.io\/goose\/install.sh | sh<\/span>\n          <span class=\"s\">echo \"$HOME\/.local\/bin\" &gt;&gt; $GITHUB_PATH<\/span>\n\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">Run goose Review<\/span>\n        <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s\">goose-review<\/span>\n        <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n          <span class=\"na\">OPENAI_API_KEY<\/span><span class=\"pi\">:<\/span> <span class=\"s\">${{ secrets.OPENAI_API_KEY }}<\/span>\n        <span class=\"na\">run<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">|<\/span>\n          <span class=\"s\">cat &gt; review-prompt.md &lt;&lt;'EOF'<\/span>\n          <span class=\"s\">Automated PR Review for PR #${{ github.event.pull_request.number }}<\/span>\n\n          <span class=\"s\">FILES CHANGED:<\/span>\n          <span class=\"s\">${{ steps.changes.outputs.files }}<\/span>\n\n          <span class=\"s\">PR CONTEXT:<\/span>\n          <span class=\"s\">- Title: ${{ github.event.pull_request.title }}<\/span>\n          <span class=\"s\">- Author: ${{ github.event.pull_request.user.login }}<\/span>\n          <span class=\"s\">- Base: ${{ github.base_ref }}<\/span>\n          <span class=\"s\">- Branch: ${{ github.head_ref }}<\/span>\n\n          <span class=\"s\">REVIEW FOCUS:<\/span>\n\n          <span class=\"s\">1. **Quick Wins** (auto-fixable):<\/span>\n             <span class=\"s\">- Linting issues<\/span>\n             <span class=\"s\">- Formatting problems<\/span>\n             <span class=\"s\">- Import organization<\/span>\n             <span class=\"s\">- Type annotations<\/span>\n\n          <span class=\"s\">2. **Risk Assessment**:<\/span>\n             <span class=\"s\">- Breaking changes?<\/span>\n             <span class=\"s\">- Database migrations?<\/span>\n             <span class=\"s\">- New dependencies?<\/span>\n             <span class=\"s\">- Performance impacts?<\/span>\n\n          <span class=\"s\">3. **Quality Checks**:<\/span>\n             <span class=\"s\">- Test coverage for new code<\/span>\n             <span class=\"s\">- Error handling completeness<\/span>\n             <span class=\"s\">- Security considerations<\/span>\n             <span class=\"s\">- Documentation updates needed?<\/span>\n\n          <span class=\"s\">4. **Architecture Review**:<\/span>\n             <span class=\"s\">- Follows our patterns?<\/span>\n             <span class=\"s\">- Proper separation of concerns?<\/span>\n             <span class=\"s\">- Consistent with codebase?<\/span>\n\n          <span class=\"s\">OUTPUT FORMAT:<\/span>\n\n          <span class=\"s\">## goose Automated Review<\/span>\n\n          <span class=\"s\">### \ud83d\udcca Summary<\/span>\n          <span class=\"s\">- **Risk Level**: [LOW\/MEDIUM\/HIGH] + explanation<\/span>\n          <span class=\"s\">- **Test Coverage**: [X%] for new\/modified code<\/span>\n          <span class=\"s\">- **Estimated Review Time**: [X minutes] for human reviewer<\/span>\n\n          <span class=\"s\">### \ud83d\udd34 Critical Issues (block merge)<\/span>\n          <span class=\"s\">[List with file:line references]<\/span>\n\n          <span class=\"s\">### \ud83d\udfe1 High Priority (fix before merge)<\/span>\n          <span class=\"s\">[List with file:line references]<\/span>\n\n          <span class=\"s\">### \ud83d\udfe2 Suggestions (consider)<\/span>\n          <span class=\"s\">[List with file:line references]<\/span>\n\n          <span class=\"s\">### What Looks Good<\/span>\n          <span class=\"s\">[Positive feedback - important for morale!]<\/span>\n\n          <span class=\"s\">### Recommended Next Steps<\/span>\n          <span class=\"s\">[Actionable list for the author]<\/span>\n\n          <span class=\"s\">### Human Reviewer: Focus Here<\/span>\n          <span class=\"s\">[Areas that need human judgment]<\/span>\n\n          <span class=\"s\">---<\/span>\n          <span class=\"s\">*Automated review by Goose \u2022 Not a substitute for human review*<\/span>\n          <span class=\"s\">EOF<\/span>\n\n          <span class=\"s\">goose run --prompt-file review-prompt.md &gt; review-output.md<\/span>\n\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">Post Review Comment<\/span>\n        <span class=\"na\">uses<\/span><span class=\"pi\">:<\/span> <span class=\"s\">actions\/github-script@v6<\/span>\n        <span class=\"na\">with<\/span><span class=\"pi\">:<\/span>\n          <span class=\"na\">github-token<\/span><span class=\"pi\">:<\/span> <span class=\"s\">${{ secrets.GITHUB_TOKEN }}<\/span>\n          <span class=\"na\">script<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">|<\/span>\n            <span class=\"s\">const fs = require('fs');<\/span>\n            <span class=\"s\">const review = fs.readFileSync('review-output.md', 'utf8');<\/span>\n\n            <span class=\"s\">await github.rest.issues.createComment({<\/span>\n              <span class=\"s\">issue_number: context.issue.number,<\/span>\n              <span class=\"s\">owner: context.repo.owner,<\/span>\n              <span class=\"s\">repo: context.repo.repo,<\/span>\n              <span class=\"s\">body: review<\/span>\n            <span class=\"s\">});<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Workflow 3: Security-Focused Review\n<\/h4>\n\n<p>For PRs touching authentication, payments, or sensitive data:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>SECURITY REVIEW: [files]\n\nTHREAT MODEL for our application:\n- User data: emails, names, addresses (PII)\n- Payment information: handled via Stripe (PCI-DSS scope)\n- Authentication: JWT tokens, bcrypt passwords\n- API keys: stored in env vars, never committed\n- User uploads: images only, max 5MB\n\nSECURITY CHECKLIST:\n\n**Authentication &amp; Authorization:**\n- [ ] All endpoints check authentication?\n- [ ] Authorization rules prevent privilege escalation?\n- [ ] Session management secure (expiry, renewal, logout)?\n- [ ] Password requirements enforced?\n- [ ] Account lockout after failed attempts?\n\n**Input Validation:**\n- [ ] All user inputs validated against schema?\n- [ ] SQL injection prevention (parameterized queries)?\n- [ ] XSS prevention (output encoding)?\n- [ ] File upload restrictions (type, size, content)?\n- [ ] API rate limiting in place?\n\n**Data Protection:**\n- [ ] PII encrypted at rest?\n- [ ] Passwords hashed with bcrypt (10+ rounds)?\n- [ ] Sensitive data not logged?\n- [ ] API keys\/secrets not hardcoded?\n- [ ] HTTPS enforced?\n\n**Security Headers:**\n- [ ] Content-Security-Policy set?\n- [ ] X-Frame-Options prevents clickjacking?\n- [ ] CSRF tokens on state-changing operations?\n- [ ] Secure cookie flags (HttpOnly, Secure, SameSite)?\n\n**Error Handling:**\n- [ ] Error messages don't leak info (stack traces, db details)?\n- [ ] Failed auth attempts logged?\n- [ ] Graceful degradation secure?\n\nFor each issue found:\n\n1. **Vulnerability**: [What's wrong]\n2. **OWASP Category**: [e.g., A03:2021 \u2013 Injection]\n3. **Attack Scenario**: [How could this be exploited]\n4. **Risk Level**: [CRITICAL\/HIGH\/MEDIUM\/LOW]\n5. **Fix**: [Specific code changes]\n6. **Verification**: [How to test the fix]\n\nCRITICAL ISSUES:\n- Implement the fix immediately\n- Run security tests to verify\n- Create a test case that would fail without the fix\n\nAfter review:\n- Security score: X\/10\n- Critical issues: [count]\n- Ready for security team review? YES\/NO\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Workflow 4: Performance Review\n<\/h4>\n\n<p>For performance-sensitive code:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>PERFORMANCE REVIEW: [files]\n\nOUR PERFORMANCE BUDGETS:\n- API response time: &lt; 200ms (p95)\n- Database queries: &lt; 100ms per query\n- Page load time: &lt; 3s\n- Memory per request: &lt; 50MB\n- Max concurrent requests: 1000+\n\nREVIEW CHECKLIST:\n\n**Database Optimization:**\n- [ ] N+1 query problems?\n- [ ] Missing indexes on queried columns?\n- [ ] SELECT * used (fetch only needed columns)?\n- [ ] Unnecessary JOINs?\n- [ ] Query results cached appropriately?\n\n**Algorithm Efficiency:**\n- [ ] Time complexity acceptable? (O(n\u00b2) is usually bad)\n- [ ] Space complexity reasonable?\n- [ ] Nested loops with large datasets?\n- [ ] Unnecessary array\/object operations?\n\n**Async\/Concurrency:**\n- [ ] Async operations parallelized where possible?\n- [ ] No blocking operations in async code?\n- [ ] Promise.all() used for concurrent operations?\n- [ ] Resource pooling for expensive operations?\n\n**Memory Management:**\n- [ ] Memory leaks (event listeners, closures)?\n- [ ] Large objects held in memory unnecessarily?\n- [ ] Streams used for large files?\n- [ ] Pagination for large result sets?\n\n**Caching Strategy:**\n- [ ] Repeated computations cached?\n- [ ] HTTP caching headers set correctly?\n- [ ] Redis\/memory cache used appropriately?\n- [ ] Cache invalidation strategy sound?\n\nFor each performance issue:\n\n1. **Problem**: [What's slow]\n2. **Current Performance**: [Measurements if available]\n3. **Why It's Slow**: [Root cause]\n4. **Optimization**: [Specific fix with code]\n5. **Expected Impact**: [Performance improvement estimate]\n6. **Trade-offs**: [Any downsides to the optimization]\n\nBENCHMARK:\n- Create a performance test for critical paths\n- Run before\/after benchmarks\n- Show the improvement\n\nFinal assessment:\n- Meets our performance budgets? YES\/NO\n- Benchmark results: [before \u2192 after]\n- Recommended load testing scenarios\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Workflow 5: Legacy Code Refactoring Review\n<\/h4>\n\n<p>When modernizing old code:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>LEGACY REFACTORING REVIEW: [files]\n\nMIGRATION CONTEXT:\nFrom: [old pattern\/version]\nTo: [new pattern\/version]\nReason: [why we're refactoring]\nConstraints:\n- [ ] Backward compatibility required? [YES\/NO]\n- [ ] Gradual rollout needed? [YES\/NO]\n- [ ] Zero downtime deployment? [YES\/NO]\n\nREFACTORING CHECKLIST:\n\n**Behavioral Equivalence:**\n1. Load existing test suite\n2. Run tests against OLD code: [results]\n3. Run tests against NEW code: [results]\n4. Any behavioral differences?\n   - If YES: Are they intentional improvements?\n   - Document each difference\n5. Add regression tests for bug fixes\n\n**Code Quality Improvements:**\n- [ ] Reduced complexity (cyclomatic complexity)?\n- [ ] Better naming and structure?\n- [ ] Removed code duplication?\n- [ ] Improved error handling?\n- [ ] Better separation of concerns?\n\n**Test Coverage:**\n- Old coverage: [X%]\n- New coverage: [Y%]\n- Gaps in new implementation:\n  - [List untested scenarios]\n- Recommended additional tests:\n  - [Specific test cases needed]\n\n**Performance Impact:**\nRun benchmarks:\n- Old implementation: [metrics]\n- New implementation: [metrics]\n- Performance change: [+\/- X%]\n- If slower: is it worth the code quality improvement?\n\n**Dependency Analysis:**\n- New dependencies added:\n  - [List with justification]\n- Dependencies removed:\n  - [List - why safe to remove]\n- Dependency version changes:\n  - [List with breaking changes noted]\n\n**Deployment Strategy:**\nBased on the risk, recommend:\n\n- [ ] **Big Bang** (all at once)\n  - Low risk, good test coverage\n  - No API changes\n  - Easy rollback\n\n- [ ] **Feature Flag** (gradual rollout)\n  - Medium risk\n  - Can test in production with subset of users\n  - Easy to revert\n\n- [ ] **Parallel Run** (both versions)\n  - High risk\n  - Critical system\n  - Compare outputs before switching\n\n**Migration Checklist:**\n- [ ] Database migrations (if any)\n- [ ] Configuration changes needed\n- [ ] Environment variable updates\n- [ ] Dependent services that need updates\n- [ ] Documentation updates\n- [ ] Runbook for deployment\n\n**Rollback Plan:**\nIf the refactoring causes issues:\n1. [Step 1 to rollback]\n2. [Step 2 to rollback]\n3. [How to verify rollback successful]\n\nFINAL ASSESSMENT:\n- Risk Level: [LOW\/MEDIUM\/HIGH]\n- Confidence Score: [0-100%] safe to deploy\n- Recommended Approach: [Big Bang\/Feature Flag\/Parallel Run]\n- Blockers: [Any issues that must be resolved first]\n- Ready for staging? YES\/NO\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Building a Team Review Culture with Goose\n<\/h3>\n\n<h4>\n  \n  \n  Creating Team Standards\n<\/h4>\n\n<p><strong>File<\/strong>: <code>.goose\/team-standards.md<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code><span class=\"gh\"># Team Code Review Standards<\/span>\n\n<span class=\"gu\">## Our Review Philosophy<\/span>\n<span class=\"p\">-<\/span> Reviews are for learning, not judging\n<span class=\"p\">-<\/span> Everyone's code gets reviewed, including seniors\n<span class=\"p\">-<\/span> Focus on code, not the coder\n<span class=\"p\">-<\/span> Ask questions, don't demand changes\n<span class=\"p\">-<\/span> Suggest alternatives, don't just criticize\n\n<span class=\"gu\">## Severity Levels<\/span>\n<span class=\"p\">-<\/span> \ud83d\udd34 CRITICAL: Security, data loss, breaking changes\n<span class=\"p\">-<\/span> \ud83d\udfe1 HIGH: Bugs, performance issues, missing tests\n<span class=\"p\">-<\/span> \ud83d\udfe2 MEDIUM: Maintainability, style, documentation\n<span class=\"p\">-<\/span> \u26aa LOW: Minor improvements, nitpicks\n\n<span class=\"gu\">## Response Time Expectations<\/span>\n<span class=\"p\">-<\/span> Critical PRs: &lt; 2 hours\n<span class=\"p\">-<\/span> Standard PRs: &lt; 1 business day\n<span class=\"p\">-<\/span> Large PRs (500+ lines): &lt; 2 business days\n\n<span class=\"gu\">## PR Size Guidelines<\/span>\n<span class=\"p\">-<\/span> Ideal: &lt; 200 lines\n<span class=\"p\">-<\/span> Maximum: &lt; 500 lines\n<span class=\"p\">-<\/span> If larger: break into multiple PRs\n\n<span class=\"gu\">## Required Reviews<\/span>\n<span class=\"p\">-<\/span> 1 approval for standard changes\n<span class=\"p\">-<\/span> 2 approvals for:\n<span class=\"p\">  -<\/span> Security-sensitive code\n<span class=\"p\">  -<\/span> Database migrations\n<span class=\"p\">  -<\/span> API changes\n<span class=\"p\">  -<\/span> Architecture changes\n\n<span class=\"gu\">## Auto-Checks Before Human Review<\/span>\n<span class=\"p\">-<\/span> [ ] CI passes\n<span class=\"p\">-<\/span> [ ] Tests cover new code (80%+)\n<span class=\"p\">-<\/span> [ ] Goose pre-review complete\n<span class=\"p\">-<\/span> [ ] Self-review checklist done\n\n<span class=\"gu\">## What to Look For<\/span>\n<span class=\"p\">-<\/span> Correctness: Does it work?\n<span class=\"p\">-<\/span> Tests: Is it tested?\n<span class=\"p\">-<\/span> Clarity: Can I understand it?\n<span class=\"p\">-<\/span> Simplicity: Is this the simplest approach?\n<span class=\"p\">-<\/span> Consistency: Does it fit our patterns?\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Prompt for Using Team Standards\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Review this PR according to our team standards in .goose\/team-standards.md:\n\n[PR details]\n\nIMPORTANT: \n- Follow our severity levels exactly\n- Keep our review philosophy in mind (constructive, not critical)\n- Use our standard format\n- Consider our response time when prioritizing issues\n\nFocus your review on what matters most to our team:\n1. Correctness and testing (most important)\n2. Security and performance\n3. Maintainability and clarity\n4. Consistency with our patterns\n\nFormat output as a friendly, constructive review comment.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Measuring Review Effectiveness\n<\/h3>\n\n<p>Track these metrics to improve your review process:<\/p>\n\n<h4>\n  \n  \n  Efficiency Metrics\n<\/h4>\n\n<p><strong>Script<\/strong>: <code>scripts\/review-metrics.sh<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\">#!\/bin\/bash<\/span>\n\n<span class=\"c\"># Time from PR creation to first review<\/span>\ngh <span class=\"nb\">pr <\/span>list <span class=\"nt\">--state<\/span> merged <span class=\"nt\">--json<\/span> number,createdAt,reviews <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--jq<\/span> <span class=\"s1\">'.[] | {pr: .number, first_review: (.reviews[0].submittedAt \/\/ \"none\")}'<\/span> <span class=\"se\">\\<\/span>\n  <span class=\"o\">&gt;<\/span> metrics\/first-review-times.json\n\n<span class=\"c\"># Review cycle time<\/span>\ngh <span class=\"nb\">pr <\/span>list <span class=\"nt\">--state<\/span> merged <span class=\"nt\">--json<\/span> number,createdAt,mergedAt,reviews <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--jq<\/span> <span class=\"s1\">'.[] | {pr: .number, cycles: (.reviews | length), total_time: .mergedAt}'<\/span> <span class=\"se\">\\<\/span>\n  <span class=\"o\">&gt;<\/span> metrics\/review-cycles.json\n\n<span class=\"c\"># Issues found in review vs production<\/span>\n<span class=\"c\"># Track in a simple CSV<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"date,pr_number,issues_in_review,issues_in_prod\"<\/span> <span class=\"o\">&gt;&gt;<\/span> metrics\/defect-escape.csv\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Quality Metrics\n<\/h4>\n\n<p>Create a review retrospective prompt:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>REVIEW RETROSPECTIVE\n\nAnalyze our last 10 merged PRs:\n\nQUESTIONS:\n1. How many issues did goose catch vs. humans?\n   - Break down by severity\n\n2. Were there any defects that made it to production?\n   - Should goose have caught them?\n   - Update review prompts to catch similar issues\n\n3. What patterns of issues appear repeatedly?\n   - Suggest adding them to our automated checks\n\n4. Review cycle analysis:\n   - Average time to first review?\n   - Average number of review rounds?\n   - Where are bottlenecks?\n\n5. goose effectiveness:\n   - False positive rate (flags that weren't issues)\n   - False negative rate (missed issues)\n   - Time saved vs. manual review\n\nRECOMMENDATIONS:\nBased on this analysis:\n- What should we add to our automated checks?\n- What prompts should we refine?\n- Where do we still need more human judgment?\n- What's working well that we should do more of?\n\nSave findings to docs\/review-retrospectives\/YYYY-MM.md\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Advanced Techniques\n<\/h3>\n\n<h4>\n  \n  \n  Multi-Perspective Review\n<\/h4>\n\n<p>Get different angles on the same code:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Review [files] from multiple perspectives:\n\nPERSPECTIVE 1 - SECURITY ANALYST:\nYou are a security expert looking for vulnerabilities.\n[Full security checklist]\n\nPERSPECTIVE 2 - PERFORMANCE ENGINEER:\nYou are a performance expert looking for inefficiencies.\n[Full performance checklist]\n\nPERSPECTIVE 3 - JUNIOR DEVELOPER:\nYou are a junior developer trying to understand this code.\nWhat's confusing? What needs better comments?\n\nPERSPECTIVE 4 - FUTURE MAINTAINER:\nYou will maintain this code in 2 years.\nWhat will make your life difficult?\n\nSynthesize findings across all perspectives and prioritize.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Contextual Learning from Past Reviews\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>LEARN FROM HISTORY:\n\nBefore reviewing [current-pr], analyze:\n1. Similar PRs we've reviewed before\n2. Issues we found in those reviews\n3. Patterns of problems in this area of the codebase\n\nTHEN review [current-pr] with extra attention to:\n- Historically problematic patterns\n- Issues that have bitten us before\n- Areas where we commonly find bugs\n\nReference specific past PRs if you find similar issues:\n\"This is similar to the issue we found in PR #123...\"\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Explaining Review Feedback\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>I'm about to post this review feedback to a developer:\n\n[Your draft review comments]\n\nBefore I post:\n1. Review my tone - is it constructive and helpful?\n2. Are any comments unclear or ambiguous?\n3. Could any feedback be misinterpreted as personal criticism?\n4. Am I explaining WHY something is an issue, not just THAT it's an issue?\n5. Did I include what's good, not just what's wrong?\n\nSuggest improvements to make this review more effective and kind.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Troubleshooting Common Review Challenges\n<\/h3>\n\n<h4>\n  \n  \n  Challenge: Too Many False Positives\n<\/h4>\n\n<p><strong>Symptom<\/strong>: goose flags things that aren't actually problems in your context.<br>\n<strong>Solution<\/strong>: Build context into your prompts:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Review [files] with these EXCEPTIONS:\n\nFALSE POSITIVES TO IGNORE:\n- console.log in \/scripts\/ (we use these for CLI tools)\n- any\/unknown types in \/types\/legacy\/ (migrating gradually)\n- TODO comments with ticket numbers (tracked in Jira)\n- Magic numbers in \/config\/ (configuration values)\n- process.env in \/config\/ (centralized config only)\n\nCONTEXT ABOUT OUR CODEBASE:\n- We use dependency injection (constructors take many params)\n- We prefer composition over inheritance (not OOP)\n- We use React's useCallback extensively (not unnecessary)\n- Our API uses snake_case (not camelCase)\n\nOnly flag genuine issues, not patterns we've consciously chosen.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Challenge: goose Misses Domain-Specific Issues\n<\/h4>\n\n<p><strong>Symptom<\/strong>: goose doesn't catch bugs that require domain knowledge.<br>\n<strong>Solution<\/strong>: Add domain context to reviews:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Review [financial-transaction-code] with this DOMAIN CONTEXT:\n\nFINANCIAL RULES:\n- All currency calculations must use Decimal type (not Number)\n- Transactions must be idempotent (safe to retry)\n- Amounts must always have 2 decimal places\n- Currency codes must be ISO 4217 (USD, EUR, etc.)\n- Negative amounts only allowed for refunds\/chargebacks\n\nBUSINESS RULES:\n- Minimum transaction: $0.50\n- Maximum transaction: $10,000\n- Refunds allowed within 90 days\n- Partial refunds must not exceed original amount\n\nCOMPLIANCE:\n- PCI-DSS: never log full card numbers\n- GDPR: include data retention policies\n- SOX: maintain audit trail for all changes\n\nFlag any violations of these rules with severity CRITICAL.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Challenge: Inconsistent Review Quality\n<\/h4>\n\n<p><strong>Symptom<\/strong>: Some reviews are thorough, others miss obvious issues.<br>\n<strong>Solution<\/strong>: Create standardized review templates:<br>\n<strong>File<\/strong>: <code>.goose\/prompts\/standard-review.md<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code><span class=\"gh\"># Standard Code Review Template<\/span>\n\n<span class=\"gu\">## PR Information<\/span>\n<span class=\"p\">-<\/span> PR: #{{pr_number}}\n<span class=\"p\">-<\/span> Files: {{files}}\n<span class=\"p\">-<\/span> Author: {{author}}\n\n<span class=\"gu\">## Pre-Flight Checks<\/span>\n<span class=\"p\">-<\/span> [ ] CI passing?\n<span class=\"p\">-<\/span> [ ] Tests included?\n<span class=\"p\">-<\/span> [ ] PR description clear?\n\n<span class=\"gu\">## Review Stages<\/span>\n\n<span class=\"gu\">### Stage 1: Quick Scan (2 min)<\/span>\n<span class=\"p\">-<\/span> Breaking changes?\n<span class=\"p\">-<\/span> Security red flags?\n<span class=\"p\">-<\/span> Missing tests?\n\nSTOP: If critical issues found, report immediately.\n\n<span class=\"gu\">### Stage 2: Detailed Review (main)<\/span>\n<span class=\"p\">-<\/span> [Full review checklist from .goose\/team-standards.md]\n\n<span class=\"gu\">### Stage 3: Suggestions (optional)<\/span>\n<span class=\"p\">-<\/span> Refactoring opportunities\n<span class=\"p\">-<\/span> Additional tests\n<span class=\"p\">-<\/span> Documentation improvements\n\n<span class=\"gu\">## Output Format<\/span>\n[Standard format from team standards]\n<span class=\"p\">\n---<\/span>\nUse this template: <span class=\"sb\">`goose review --template .goose\/prompts\/standard-review.md`<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Integration with Your Dev Tools\n<\/h3>\n\n<h4>\n  \n  \n  VS Code Integration\n<\/h4>\n\n<p><code>.vscode\/tasks.json<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"version\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2.0.0\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"tasks\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"w\">\n    <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"label\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"Goose: Review Current File\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"type\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"shell\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"command\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"goose\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"args\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"w\">\n        <\/span><span class=\"s2\">\"prompt\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n        <\/span><span class=\"s2\">\"Review ${file} for issues. Use our standards in .goose\/team-standards.md\"<\/span><span class=\"w\">\n      <\/span><span class=\"p\">],<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"presentation\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n        <\/span><span class=\"nl\">\"reveal\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"always\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n        <\/span><span class=\"nl\">\"panel\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"new\"<\/span><span class=\"w\">\n      <\/span><span class=\"p\">}<\/span><span class=\"w\">\n    <\/span><span class=\"p\">},<\/span><span class=\"w\">\n    <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"label\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"Goose: Review Git Changes\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"type\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"shell\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"command\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"bash\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"args\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"w\">\n        <\/span><span class=\"s2\">\"-c\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n        <\/span><span class=\"s2\">\"goose prompt <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">Review my uncommitted changes: $(git diff --name-only)<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">\"<\/span><span class=\"w\">\n      <\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">]<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Git Aliases\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code># Add to ~\/.gitconfig\n[alias]\n    review = \"!goose prompt 'Review my staged changes before committing'\"\n    review-pr = \"!f() { goose prompt \\\"Review PR #$1 for merge readiness\\\"; }; f\"\n    review-security = \"!goose prompt --template .goose\/prompts\/security-review.md\"\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Real-World Example: Complete Review Session\n<\/h3>\n\n<p>Let's walk through reviewing a real feature PR:<br>\n<strong>Scenario<\/strong>: Developer submits PR adding user profile editing.<\/p>\n<h4>\n  \n  \n  Stage 1: Initial Triage\n<\/h4>\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose session start <span class=\"s2\">\"review-pr-1234\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Quick triage of PR #1234: \"Add user profile editing\"\n\nFILES CHANGED:\n- src\/controllers\/user-controller.js (modified, +89 lines)\n- src\/services\/user-service.js (modified, +134 lines)\n- src\/models\/user.js (modified, +45 lines)\n- tests\/user-service.test.js (new, +156 lines)\n- docs\/api.md (modified, +23 lines)\n\nQUICK CHECKS (30 seconds each):\n1. Does CI pass? \u2713\/\u2717\n2. Are tests included? \u2713\/\u2717\n3. Is test coverage adequate (80%+)? \u2713\/\u2717\n4. Any obvious security issues? \u2713\/\u2717\n5. Documentation updated? \u2713\/\u2717\n\nIf any \u2717, flag as NEEDS WORK with specifics.\nIf all \u2713, proceed to detailed review.\n<\/code><\/pre>\n\n<\/div>\n\n<h4>\n  \n  \n  goose Output:\n<\/h4>\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>TRIAGE RESULTS:\n\n\u2705 CI Status: Passing (all 234 tests)\n\u2705 Tests Included: Yes (156 new test cases)\n\u2705 Test Coverage: 87% (exceeds requirement)\n\u26a0\ufe0f  Security: Potential issue found\n\u2705 Documentation: Updated\n\n\ud83d\udd34 BLOCKER FOUND:\nFile: src\/services\/user-service.js:78\nIssue: User input not validated before database update\nImpact: SQL injection risk\nSeverity: CRITICAL\n\nRECOMMENDATION: Request changes. Security issue must be fixed before detailed review.\n<\/code><\/pre>\n\n<\/div>\n\n<h4>\n  \n  \n  Stage 2: Developer Fixes Issue\n<\/h4>\n\n<p>Developer pushes fix. Resume review:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Security issue fixed in latest commit. \n\nContinue with detailed review of PR #1234:\n\nARCHITECTURAL REVIEW:\n- Follows our Controller\u2192Service\u2192Model pattern?\n- Business logic properly in service layer?\n- No direct DB access from controller?\n- Error handling consistent with our patterns?\n\nCODE QUALITY:\n- Naming clear and consistent?\n- Functions focused (single responsibility)?\n- Comments explain \"why\", not \"what\"?\n- No code duplication?\n\nEDGE CASES:\n- What happens with:\n  - Empty string inputs?\n  - Very long inputs (SQL varchar limits)?\n  - Special characters in names?\n  - Concurrent updates to same profile?\n  - Non-existent user IDs?\n\nRun tests for each edge case. If not covered, suggest additional tests.\n\nPERFORMANCE:\n- Any N+1 query issues?\n- Unnecessary data fetching?\n- Missing indexes on queried columns?\n\nFormat as a structured review comment.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  goose Output:\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code><span class=\"gu\">## Code Review: PR #1234<\/span>\n\n<span class=\"gu\">### \u2705 Architecture (9\/10)<\/span>\n\n<span class=\"gs\">**Strengths:**<\/span>\n<span class=\"p\">-<\/span> Perfect adherence to Controller\u2192Service\u2192Model layering\n<span class=\"p\">-<\/span> Business logic correctly isolated in service layer\n<span class=\"p\">-<\/span> Consistent with existing patterns\n\n<span class=\"gs\">**Minor suggestion:**<\/span>\n<span class=\"p\">-<\/span> Line 134: Consider extracting validation logic to a separate validator function for reusability\n\n<span class=\"gu\">### \u26a0\ufe0f  Edge Case Handling (6\/10 - NEEDS IMPROVEMENT)<\/span>\n\n<span class=\"gs\">**Issues Found:**<\/span>\n<span class=\"p\">\n1.<\/span> <span class=\"gs\">**MEDIUM**<\/span>: Empty string handling (user-service.js:89)\njavascript\n   \/\/ Current code allows empty strings\n   if (profileData.bio) { ... }\n\n   \/\/ Should validate:\n   if (profileData.bio &amp;&amp; profileData.bio.trim().length &gt; 0) { ... }\n<span class=\"p\">\n2.<\/span> <span class=\"gs\">**MEDIUM**<\/span>: Missing length validation (user-service.js:92)\n<span class=\"p\">   -<\/span> Database column: VARCHAR(500) for bio\n<span class=\"p\">   -<\/span> No validation before insert\n<span class=\"p\">   -<\/span> Could cause database errors\n<span class=\"p\">   -<\/span> <span class=\"gs\">**Fix**<\/span>: Add validation: <span class=\"sb\">`if (bio.length &gt; 500) throw new ValidationError(...)`<\/span>\n<span class=\"p\">\n3.<\/span> <span class=\"gs\">**HIGH**<\/span>: Concurrent update handling (user-service.js:78-95)\n<span class=\"p\">   -<\/span> No optimistic locking\n<span class=\"p\">   -<\/span> Last write wins (could lose data)\n<span class=\"p\">   -<\/span> <span class=\"gs\">**Tested scenario**<\/span>: Two users update same profile simultaneously\n<span class=\"p\">   -<\/span> <span class=\"gs\">**Result**<\/span>: Second update overwrites first without warning\n<span class=\"p\">   -<\/span> <span class=\"gs\">**Fix**<\/span>: Add version field or updated_at check\n\n<span class=\"gs\">**Suggested Tests to Add:**<\/span>\njavascript\ndescribe('edge cases', () =&gt; {\n  it('should reject empty bio after trim', async () =&gt; {\n    await expect(\n      userService.updateProfile(userId, { bio: '   ' })\n    ).rejects.toThrow(ValidationError);\n  });\n\n  it('should reject bio exceeding 500 chars', async () =&gt; {\n    const longBio = 'a'.repeat(501);\n    await expect(\n      userService.updateProfile(userId, { bio: longBio })\n    ).rejects.toThrow(ValidationError);\n  });\n\n  it('should handle concurrent updates gracefully', async () =&gt; {\n    \/\/ Test implementation\n  });\n});<span class=\"sb\">\n\n\n<\/span><span class=\"gu\">### \u2705 Performance (9\/10)<\/span>\n\n<span class=\"gs\">**Strengths:**<\/span>\n<span class=\"p\">-<\/span> No N+1 queries detected\n<span class=\"p\">-<\/span> Efficient single query for profile update\n<span class=\"p\">-<\/span> Appropriate use of indexes\n\n<span class=\"gs\">**Optimization opportunity:**<\/span>\n<span class=\"p\">-<\/span> Line 112: Fetches entire user object when only ID needed\n<span class=\"p\">-<\/span> <span class=\"gs\">**Current**<\/span>: <span class=\"sb\">`SELECT * FROM users WHERE id = ?`<\/span>\n<span class=\"p\">-<\/span> <span class=\"gs\">**Optimized**<\/span>: <span class=\"sb\">`SELECT id FROM users WHERE id = ?`<\/span>\n<span class=\"p\">-<\/span> <span class=\"gs\">**Impact**<\/span>: Minor, but good practice\n\n<span class=\"gu\">### \ud83c\udfaf Overall Assessment<\/span>\n\n<span class=\"gs\">**Ready for merge**<\/span>: NO (after addressing MEDIUM\/HIGH issues)\n\n<span class=\"gs\">**Estimated fix time**<\/span>: 1-2 hours\n\n<span class=\"gs\">**Priority fixes:**<\/span>\n<span class=\"p\">1.<\/span> \u2705 CRITICAL: SQL injection (FIXED in latest commit)\n<span class=\"p\">2.<\/span> \ud83d\udfe1 HIGH: Concurrent update handling\n<span class=\"p\">3.<\/span> \ud83d\udfe1 MEDIUM: Input validation (empty strings, length)\n<span class=\"p\">4.<\/span> \ud83d\udfe2 LOW: Query optimization\n\n<span class=\"gs\">**What's Good**<\/span> (don't forget the positives!):\n<span class=\"p\">-<\/span> Excellent test coverage (87%)\n<span class=\"p\">-<\/span> Clean, readable code\n<span class=\"p\">-<\/span> Good documentation\n<span class=\"p\">-<\/span> Follows team patterns\n\n<span class=\"gs\">**Recommended Next Steps for Author:**<\/span>\n<span class=\"p\">1.<\/span> Add optimistic locking or version checking\n<span class=\"p\">2.<\/span> Implement input validation with helpful error messages\n<span class=\"p\">3.<\/span> Add the suggested edge case tests\n<span class=\"p\">4.<\/span> Consider the query optimization\n\n<span class=\"gs\">**For Human Reviewers:**<\/span>\nFocus your time on:\n<span class=\"p\">-<\/span> Validating the concurrent update solution\n<span class=\"p\">-<\/span> Reviewing the business logic for profile restrictions\n<span class=\"p\">-<\/span> Checking if the API changes are backward compatible\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Stage 3: Interactive Review Session\n<\/h4>\n\n<p>After initial review, have a conversation with goose:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Developer Question: \"For the concurrent update issue, what's better: \noptimistic locking or a version field?\"\n\nGoose Response Analysis:\nCompare both approaches for our use case:\n- Our database: PostgreSQL\n- Update frequency: Low (users rarely edit profiles simultaneously)\n- Consistency requirements: Medium (okay if occasional conflict)\n- Existing patterns: Check what we use elsewhere in the codebase\n\nRecommend the simpler approach that fits our patterns.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  goose Output:\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>CONCURRENT UPDATE SOLUTIONS COMPARISON:\n\n**Option 1: Version Field (Optimistic Locking)**\nsql\nALTER TABLE users ADD COLUMN version INTEGER DEFAULT 0;\n\njavascript\n\/\/ Update with version check\nconst result = await User.update(\n  { ...updates, version: currentVersion + 1 },\n  { where: { id: userId, version: currentVersion } }\n);\n\nif (result.rowCount === 0) {\n  throw new ConflictError('Profile was updated by another user');\n}\n\n**Pros:**\n- Explicit versioning\n- Easy to reason about\n- Common pattern\n\n**Cons:**\n- Requires schema change\n- Another field to maintain\n\n**Option 2: Updated_at Timestamp Check**\njavascript\n\/\/ We already have updated_at column\nconst currentUpdatedAt = await User.findByPk(userId, { \n  attributes: ['updated_at'] \n});\n\nconst result = await User.update(\n  updates,\n  { \n    where: { \n      id: userId, \n      updated_at: currentUpdatedAt \n    } \n  }\n);\n\nif (result.rowCount === 0) {\n  throw new ConflictError('Profile was modified. Please refresh and try again.');\n}\n\n**Pros:**\n- No schema change needed\n- We already track updated_at\n- Simpler migration\n\n**Cons:**\n- Timestamp precision might cause issues\n- Less explicit than version field\n\n**What we use elsewhere:**\nChecked codebase... We use updated_at checks in:\n- src\/services\/post-service.js\n- src\/services\/settings-service.js\n\n**RECOMMENDATION: Option 2 (updated_at check)**\n\nConfidence: 85%\n\nReasoning:\n1. Consistent with existing patterns\n2. No migration needed\n3. Profile updates are low-frequency\n4. Simpler implementation\n5. Updated_at is already indexed\n\n**Implementation:**\nI can implement this now if you'd like. Should I proceed?\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Creating Your Review Prompt Library\n<\/h3>\n\n<p>Build a collection of reusable prompts:<\/p>\n\n<h4>\n  \n  \n  Directory Structure:\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>.goose\/\n\u251c\u2500\u2500 prompts\/\n\u2502   \u251c\u2500\u2500 quick-review.md\n\u2502   \u251c\u2500\u2500 security-review.md\n\u2502   \u251c\u2500\u2500 performance-review.md\n\u2502   \u251c\u2500\u2500 refactoring-review.md\n\u2502   \u251c\u2500\u2500 api-review.md\n\u2502   \u2514\u2500\u2500 test-review.md\n\u251c\u2500\u2500 team-standards.md\n\u2514\u2500\u2500 config.yaml\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Example:<\/strong> <code>.goose\/prompts\/api-review.md<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code><span class=\"gh\"># API Endpoint Review<\/span>\n\nReview {{files}} as a new\/modified API endpoint:\n\n<span class=\"gu\">## API Standards Check<\/span>\n\n<span class=\"gs\">**RESTful Conventions:**<\/span>\n<span class=\"p\">-<\/span> [ ] Correct HTTP method (GET\/POST\/PUT\/DELETE\/PATCH)\n<span class=\"p\">-<\/span> [ ] Proper status codes (200, 201, 400, 404, 500, etc.)\n<span class=\"p\">-<\/span> [ ] Resource naming (plural nouns, kebab-case)\n<span class=\"p\">-<\/span> [ ] Proper use of path params vs query params\n\n<span class=\"gs\">**Request Validation:**<\/span>\n<span class=\"p\">-<\/span> [ ] Input schema validation (Joi\/Yup\/Zod)\n<span class=\"p\">-<\/span> [ ] Required fields enforced\n<span class=\"p\">-<\/span> [ ] Data types validated\n<span class=\"p\">-<\/span> [ ] Size limits on strings\/arrays\n<span class=\"p\">-<\/span> [ ] Sanitization of user input\n\n<span class=\"gs\">**Response Format:**<\/span>\n<span class=\"p\">-<\/span> [ ] Consistent response structure\n<span class=\"p\">-<\/span> [ ] Proper error format: <span class=\"sb\">`{ error: \"message\", code: \"ERROR_CODE\" }`<\/span>\n<span class=\"p\">-<\/span> [ ] Success format: <span class=\"sb\">`{ data: {...}, meta: {...} }`<\/span>\n<span class=\"p\">-<\/span> [ ] Pagination for lists: <span class=\"sb\">`{ data: [], pagination: { page, limit, total } }`<\/span>\n\n<span class=\"gs\">**Security:**<\/span>\n<span class=\"p\">-<\/span> [ ] Authentication required (unless public)\n<span class=\"p\">-<\/span> [ ] Authorization checks (user can access this resource)\n<span class=\"p\">-<\/span> [ ] Rate limiting configured\n<span class=\"p\">-<\/span> [ ] CORS properly configured\n<span class=\"p\">-<\/span> [ ] No sensitive data in logs\n\n<span class=\"gs\">**Documentation:**<\/span>\n<span class=\"p\">-<\/span> [ ] OpenAPI\/Swagger documentation\n<span class=\"p\">-<\/span> [ ] Example requests\/responses\n<span class=\"p\">-<\/span> [ ] Error codes documented\n<span class=\"p\">-<\/span> [ ] Authentication requirements clear\n\n<span class=\"gs\">**Testing:**<\/span>\n<span class=\"p\">-<\/span> [ ] Success cases tested\n<span class=\"p\">-<\/span> [ ] Error cases tested (400, 401, 403, 404)\n<span class=\"p\">-<\/span> [ ] Edge cases tested\n<span class=\"p\">-<\/span> [ ] Integration tests for external dependencies\n\n<span class=\"gs\">**Backward Compatibility:**<\/span>\n<span class=\"p\">-<\/span> [ ] Breaking changes to existing endpoints?\n<span class=\"p\">-<\/span> [ ] Version bump needed?\n<span class=\"p\">-<\/span> [ ] Migration path for clients?\n<span class=\"p\">-<\/span> [ ] Deprecation warnings if needed\n\n<span class=\"gu\">## Review Output<\/span>\n\nFor each issue found:\n<span class=\"p\">-<\/span> <span class=\"gs\">**Category**<\/span>: [Request\/Response\/Security\/Documentation\/Testing]\n<span class=\"p\">-<\/span> <span class=\"gs\">**Severity**<\/span>: [CRITICAL\/HIGH\/MEDIUM\/LOW]\n<span class=\"p\">-<\/span> <span class=\"gs\">**Issue**<\/span>: [Description]\n<span class=\"p\">-<\/span> <span class=\"gs\">**Location**<\/span>: [File:Line]\n<span class=\"p\">-<\/span> <span class=\"gs\">**Fix**<\/span>: [Specific suggestion]\n\n<span class=\"gu\">## API Compatibility Analysis<\/span>\n\nCompare with existing API patterns:\n<span class=\"p\">1.<\/span> Does response format match our other endpoints?\n<span class=\"p\">2.<\/span> Is error handling consistent?\n<span class=\"p\">3.<\/span> Does it follow our authentication pattern?\n<span class=\"p\">4.<\/span> Is it documented like our other endpoints?\n\n<span class=\"gu\">## Performance Considerations<\/span>\n<span class=\"p\">\n-<\/span> Potential for high traffic?\n<span class=\"p\">-<\/span> Database query efficiency?\n<span class=\"p\">-<\/span> Need for caching?\n<span class=\"p\">-<\/span> Rate limiting appropriate?\n\n<span class=\"gu\">## Final Checklist<\/span>\n<span class=\"p\">\n-<\/span> [ ] Follows REST conventions\n<span class=\"p\">-<\/span> [ ] Input validated\n<span class=\"p\">-<\/span> [ ] Properly secured\n<span class=\"p\">-<\/span> [ ] Well documented\n<span class=\"p\">-<\/span> [ ] Thoroughly tested\n<span class=\"p\">-<\/span> [ ] Backward compatible\n<span class=\"p\">-<\/span> [ ] Performance acceptable\n\n<span class=\"gs\">**Ready for production**<\/span>: YES\/NO\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Continuous Improvement\n<\/h3>\n\n<h4>\n  \n  \n  Weekly Review Retrospective\n<\/h4>\n\n<p>Run this every Friday:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\">#!\/bin\/bash<\/span>\n<span class=\"c\"># scripts\/weekly-review-retrospective.sh<\/span>\n\n<span class=\"nv\">WEEK_START<\/span><span class=\"o\">=<\/span><span class=\"si\">$(<\/span><span class=\"nb\">date<\/span> <span class=\"nt\">-d<\/span> <span class=\"s2\">\"last monday\"<\/span> +%Y-%m-%d<span class=\"si\">)<\/span>\n<span class=\"nv\">WEEK_END<\/span><span class=\"o\">=<\/span><span class=\"si\">$(<\/span><span class=\"nb\">date<\/span> +%Y-%m-%d<span class=\"si\">)<\/span>\n\ngoose prompt <span class=\"o\">&lt;&lt;<\/span><span class=\"no\">EOF<\/span><span class=\"sh\">\nWeekly Code Review Retrospective: <\/span><span class=\"nv\">$WEEK_START<\/span><span class=\"sh\"> to <\/span><span class=\"nv\">$WEEK_END<\/span><span class=\"sh\">\n\nAnalyze all PRs merged this week:\n\n<\/span><span class=\"si\">$(<\/span>gh <span class=\"nb\">pr <\/span>list <span class=\"nt\">--state<\/span> merged <span class=\"nt\">--search<\/span> <span class=\"s2\">\"merged:&gt;<\/span><span class=\"nv\">$WEEK_START<\/span><span class=\"s2\">\"<\/span> <span class=\"nt\">--json<\/span> number,title,reviews<span class=\"si\">)<\/span><span class=\"sh\">\n\nMETRICS TO CALCULATE:\n1. Total PRs reviewed: [count]\n2. Average time to first review: [hours]\n3. Average number of review rounds: [count]\n4. Common issues found:\n   - By category (security, performance, style, etc.)\n   - By severity\n5. Goose effectiveness:\n   - Issues caught by Goose vs humans\n   - False positives from Goose\n   - Time saved estimates\n\nTRENDS:\n- Are we getting faster at reviews?\n- Are we finding fewer issues (improving code quality)?\n- Are same issues appearing repeatedly (need automation)?\n\nIMPROVEMENTS FOR NEXT WEEK:\n- New automated checks to add\n- Prompt templates to create\/update\n- Team standards to clarify\n- Training needs identified\n\nOUTPUT:\nSave to docs\/retrospectives\/<\/span><span class=\"si\">$(<\/span><span class=\"nb\">date<\/span> +%Y-week-%U<span class=\"si\">)<\/span><span class=\"sh\">.md\n<\/span><span class=\"no\">EOF\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Learning from Production Issues\n<\/h4>\n\n<p>When bugs escape to production:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>POST-INCIDENT REVIEW:\n\nPRODUCTION ISSUE: {{issue_description}}\nDiscovered: {{date}}\nSeverity: {{impact}}\n\nCODE REVIEW FORENSICS:\n1. Was this code reviewed? PR #{{number}}\n2. Pull up the review comments\n3. Should this issue have been caught?\n\nANALYSIS:\n- What type of issue was it?\n  - Logic error\n  - Edge case\n  - Performance issue\n  - Security vulnerability\n\n- Why wasn't it caught in review?\n  - Not tested?\n  - Test didn't cover this scenario?\n  - Reviewer missed it?\n  - Goose didn't flag it?\n\n- What could prevent this in the future?\n  - Add to automated checks\n  - Update review checklist\n  - Improve test coverage requirements\n  - Add specific prompt for this pattern\n\nACTION ITEMS:\n1. Update review prompts to catch similar issues\n2. Add to automated test scenarios\n3. Document in team-standards.md\n4. Share learnings in team meeting\n\nSave learnings to docs\/incident-learnings\/{{incident-id}}.md\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Best Practices Summary\n<\/h3>\n\n<h4>\n  \n  \n  Do's \u2705\n<\/h4>\n\n<ol>\n<li>\n<strong>Provide Context<\/strong>: Always include relevant background, constraints, and standards<\/li>\n<li>\n<strong>Use Severity Levels<\/strong>: Prioritize issues consistently (Critical\/High\/Medium\/Low)<\/li>\n<li>\n<strong>Verify Fixes<\/strong>: Have Goose implement and test critical fixes before presenting<\/li>\n<li>\n<strong>Be Specific<\/strong>: Reference exact files, lines, and code patterns<\/li>\n<li>\n<strong>Build Incrementally<\/strong>: Start with quick checks, then deep dive<\/li>\n<li>\n<strong>Reference Standards<\/strong>: Point to your team's documented conventions<\/li>\n<li>\n<strong>Track Metrics<\/strong>: Measure effectiveness and iterate on prompts<\/li>\n<li>\n<strong>Stay Positive<\/strong>: Include what's good, not just what's wrong<\/li>\n<li>\n<strong>Learn Continuously<\/strong>: Update prompts based on what works<\/li>\n<li>\n<strong>Human-in-Loop<\/strong>: Use goose to augment, not replace, human judgment<\/li>\n<\/ol>\n\n<h4>\n  \n  \n  Don'ts \u274c\n<\/h4>\n\n<ol>\n<li>\n<strong>Don't Be Vague<\/strong>: \"Review this code\" \u2192 Specify what to look for<\/li>\n<li>\n<strong>Don't Assume Context<\/strong>: goose doesn't know your codebase intimately<\/li>\n<li>\n<strong>Don't Skip Verification<\/strong>: Always validate AI suggestions before applying<\/li>\n<li>\n<strong>Don't Ignore False Positives<\/strong>: Update prompts to reduce noise<\/li>\n<li>\n<strong>Don't Over-Automate<\/strong>: Some things need human judgment (architecture, UX)<\/li>\n<li>\n<strong>Don't Forget Security<\/strong>: Always include security in review criteria<\/li>\n<li>\n<strong>Don't Review Giant PRs<\/strong>: Break them down first, or review incrementally<\/li>\n<li>\n<strong>Don't Neglect Documentation<\/strong>: Include docs in review scope<\/li>\n<li>\n<strong>Don't Deploy Blindly<\/strong>: Review AI-generated fixes before committing<\/li>\n<li>\n<strong>Don't Forget to Iterate<\/strong>: Improve your prompts based on results<\/li>\n<\/ol>\n\n<h3>\n  \n  \n  Conclusion\n<\/h3>\n\n<p>Effective code review with goose isn't about replacing human reviewers; it's about making them more effective. By crafting thoughtful prompts and building structured workflows, you can:<\/p>\n\n<ul>\n<li>Catch more issues earlier, before human reviewers spend time<\/li>\n<li>Focus human attention on architecture, design, and complex logic<\/li>\n<li>Maintain consistency across all reviews, regardless of reviewer<\/li>\n<li>Speed up feedback loops with automated initial reviews<\/li>\n<li>Improve code quality through systematic, comprehensive checks<\/li>\n<li>Learn continuously by tracking what works and refining your approach<\/li>\n<\/ul>\n\n<p>The key is treating goose as a junior reviewer that you're training. Start with the basics from the <a href=\"https:\/\/dev.to\/lymah\/best-practices-for-prompt-engineering-with-goose-3m6h\">general prompting guide<\/a>, then build specialized review workflows that fit your team's unique needs and standards<\/p>\n\n<p>Your review process will improve over time as you:<\/p>\n\n<ul>\n<li>Refine prompts based on what issues they catch<\/li>\n<li>Add domain-specific checks for your application<\/li>\n<li>Build a library of reusable templates<\/li>\n<li>Track metrics and iterate on effectiveness<\/li>\n<\/ul>\n\n<p>Start with one workflow, measure its impact, and expand from there. Code review with goose is a journey of continuous improvement\u2014just like the code itself.<\/p>\n\n<h4>\n  \n  \n  Resources\n<\/h4>\n\n<ul>\n<li><a href=\"https:\/\/block.github.io\/goose\/\" rel=\"noopener noreferrer\">goose Documentation<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/block\/goose\" rel=\"noopener noreferrer\">goose GitHub<\/a><\/li>\n<li>\n<a href=\"https:\/\/dev.to\/lymah\/lymah\/best-practices-for-prompt-engineering-with-goose-3m6h\">Prompt Engineering Guide<\/a>: Best Practices for Prompt Engineering with goose<\/li>\n<li>Getting Started Guide: <a href=\"https:\/\/dev.to\/lymah\/getting-started-with-goose-on-windows-30bh\">Getting Started with goose on Windows<\/a>\n<\/li>\n<li>Community: <a href=\"https:\/\/discord.gg\/block-opensource\" rel=\"noopener noreferrer\">Discord<\/a> | <a href=\"https:\/\/github.com\/block\/goose\/discussions\" rel=\"noopener noreferrer\">GitHub Discussions<\/a>\n<\/li>\n<\/ul>\n\n\n\n\n<p><em>Building effective code review workflows with goose? Share your prompts and learnings with the community! We'd love to hear what's working for your team.<\/em><\/p>\n\n","category":["goos","ai","opensource","mcp"]},{"title":"Configuring goose for Team Environments and Shared Workflows","pubDate":"Sun, 26 Oct 2025 05:46:37 +0000","link":"https:\/\/dev.to\/lymah\/configuring-goose-for-team-environments-and-shared-workflows-5ehn","guid":"https:\/\/dev.to\/lymah\/configuring-goose-for-team-environments-and-shared-workflows-5ehn","description":"<h3>\n  \n  \n  What You'll Learn\n<\/h3>\n\n<p>goose works beautifully for individual developers, but scaling it across a team requires thoughtful configuration management and workflow design. This comprehensive guide teaches you how to:<\/p>\n\n<ul>\n<li>Set up consistent goose configurations across team members<\/li>\n<li>Manage shared extensions and custom tooling<\/li>\n<li>Create team-wide workflows and best practices<\/li>\n<li>Handle API keys and secrets securely<\/li>\n<li>Version control configuration files<\/li>\n<li>Troubleshoot common team environment issues<\/li>\n<li>Establish governance and usage policies<\/li>\n<li>Monitor team usage and costs<\/li>\n<\/ul>\n\n<p><strong>Who This Is For<\/strong>: Engineering managers, DevOps engineers, team leads, and developers working in collaborative environments.<\/p>\n\n<h2>\n  \n  \n  Table of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>\nUnderstanding goose Configuration\n\n<ul>\n<li>Configuration File Locations<\/li>\n<li>Configuration Structure<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nTeam Configuration Strategies\n\n<ul>\n<li>Strategy 1: Shared Base Configuration<\/li>\n<li>Strategy 2: Per-Environment Configurations<\/li>\n<li>Strategy 3: Team Templates<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nManaging API Keys and Secrets\n\n<ul>\n<li>Recommended Approach: Environment Variables<\/li>\n<li>Alternative: Secret Management Services<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nVersion Control Best Practices\n\n<ul>\n<li>What to Commit<\/li>\n<li>Configuration Versioning<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nShared Extensions and Tooling\n\n<ul>\n<li>Example: Company API Extension<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nCreating Team Workflows\n\n<ul>\n<li>Workflow Documentation Template<\/li>\n<li>Common Workflow Library<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nOnboarding New Team Members\n\n<ul>\n<li>Onboarding Checklist<\/li>\n<li>Onboarding Buddy System<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nTroubleshooting Common Issues\n\n<ul>\n<li>Issue 1: Extension Not Loading<\/li>\n<li>Issue 2: API Rate Limits<\/li>\n<li>Issue 3: Configuration Drift<\/li>\n<li>Issue 4: Slow Performance<\/li>\n<li>Issue 5: Permission Errors<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nGovernance and Policies\n\n<ul>\n<li>Usage Policy Template<\/li>\n<li>Access Control<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nMonitoring and Cost Management\n\n<ul>\n<li>Cost Tracking Dashboard<\/li>\n<li>Usage Analytics<\/li>\n<li>Budget Alerts<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nCase Studies\n\n<ul>\n<li>Case Study 1: Startup (15 developers)<\/li>\n<li>Case Study 2: Mid-size Company (50 developers)<\/li>\n<li>Case Study 3: Enterprise (200+ developers)<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nConclusion\n\n<ul>\n<li>Quick Start Recommendations by Team Size<\/li>\n<li>Next Steps<\/li>\n<li>Resources<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Introduction\n<\/h2>\n\n<p>You've introduced goose to your team, and individual developers are seeing great productivity gains. But now you're facing challenges:<\/p>\n\n<ul>\n<li>\"It works on my machine\"<\/li>\n<li>syndrome with different configurations<\/li>\n<li>Inconsistent extension setups across the team<\/li>\n<li>Confusion about which LLM provider to use<\/li>\n<li>Security concerns about API key management<\/li>\n<li>Difficulty tracking costs across team members<\/li>\n<li>No standard workflows for common tasks<\/li>\n<\/ul>\n\n<p>Sound familiar? You're not alone. While goose excels as a personal AI assistant, transforming it into a team productivity tool requires intentional configuration management and workflow design.<br>\nThis guide walks you through battle-tested approaches for deploying goose across teams of any size, from small startups to enterprise organizations.<\/p>\n<h2>\n  \n  \n  Understanding goose Configuration\n<\/h2>\n\n<p>Before diving into team setups, let's understand how goose configuration works.<\/p>\n<h3>\n  \n  \n  Configuration File Locations\n<\/h3>\n\n<p>goose stores its configuration in different locations depending on your operating system:<\/p>\n\n<p><strong>Linux\/macOS:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>~\/.config\/block\/goose\/config.yaml\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Windows:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>%APPDATA%\\Block\\goose\\config\\config.yaml\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>For more details, see the <a href=\"https:\/\/block.github.io\/goose\/docs\/guides\/config-file\/\" rel=\"noopener noreferrer\">official config file documentation<\/a>.<\/p>\n\n<h3>\n  \n  \n  Configuration Structure\n<\/h3>\n\n<p>A typical goose configuration file looks like this:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"c1\"># Model provider configuration<\/span>\n<span class=\"na\">providers<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">openai<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">model<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gpt-4o<\/span>\n    <span class=\"na\">api_key_env<\/span><span class=\"pi\">:<\/span> <span class=\"s\">OPENAI_API_KEY<\/span>\n\n<span class=\"c1\"># Extension configuration<\/span>\n<span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">developer<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">enabled<\/span><span class=\"pi\">:<\/span> <span class=\"kc\">true<\/span>\n\n  <span class=\"na\">filesystem<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uvx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">mcp-filesystem\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n\n  <span class=\"na\">github<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">npx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">-y\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">@modelcontextprotocol\/server-github\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">GITHUB_TOKEN<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${GITHUB_TOKEN}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n\n<span class=\"c1\"># Session preferences (optional)<\/span>\n<span class=\"na\">preferences<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">default_model<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gpt-4o<\/span>\n  <span class=\"na\">max_tokens<\/span><span class=\"pi\">:<\/span> <span class=\"m\">4000<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Key sections<\/strong><\/p>\n\n<ol>\n<li>\n<strong>Providers<\/strong>: LLM configuration (OpenAI, Anthropic, etc.)<\/li>\n<li>\n<strong>Extensions<\/strong>: MCP servers and custom tools<\/li>\n<li>\n<strong>Preferences<\/strong>: User-specific settings<\/li>\n<\/ol>\n\n<h2>\n  \n  \n  Team Configuration Strategies\n<\/h2>\n\n<p>There are several approaches to managing goose configurations across teams. Choose based on your team size, security requirements, and organizational structure.<\/p>\n\n<h3>\n  \n  \n  Strategy 1: Shared Base Configuration\n<\/h3>\n\n<p><strong>Best for<\/strong>: Small teams (5-15 people), startups, unified tech stacks<br>\n<strong>How it works<\/strong>: Maintain a single base configuration file in version control that all team members use as their starting point.<\/p>\n\n<p><strong>Implementation<\/strong><\/p>\n\n<ol>\n<li>Create base configuration:\n<code>.goose\/team-config.yaml<\/code> (in your project repo):\n<\/li>\n<\/ol>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"c1\"># Team Base Configuration<\/span>\n<span class=\"c1\"># Last updated: 2025-01-15<\/span>\n<span class=\"c1\"># Maintained by: Platform Team<\/span>\n\n<span class=\"na\">providers<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">openai<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">model<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gpt-4o-mini<\/span>  <span class=\"c1\"># Cost-effective default<\/span>\n    <span class=\"na\">api_key_env<\/span><span class=\"pi\">:<\/span> <span class=\"s\">OPENAI_API_KEY<\/span>\n\n<span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"c1\"># Built-in tools<\/span>\n  <span class=\"na\">developer<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">enabled<\/span><span class=\"pi\">:<\/span> <span class=\"kc\">true<\/span>\n\n  <span class=\"c1\"># Team-specific extensions<\/span>\n  <span class=\"na\">company_api<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uvx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">company-mcp-server\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">COMPANY_API_KEY<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${COMPANY_API_KEY}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n\n  <span class=\"c1\"># GitHub integration<\/span>\n  <span class=\"na\">github<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">npx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">-y\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">@modelcontextprotocol\/server-github\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">GITHUB_TOKEN<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${GITHUB_TOKEN}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n\n  <span class=\"c1\"># Jira integration<\/span>\n  <span class=\"na\">jira<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uvx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">mcp-jira\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">JIRA_URL<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${JIRA_URL}\"<\/span>\n      <span class=\"na\">JIRA_EMAIL<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${JIRA_EMAIL}\"<\/span>\n      <span class=\"na\">JIRA_API_TOKEN<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${JIRA_API_TOKEN}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n\n<span class=\"na\">preferences<\/span><span class=\"pi\">:<\/span>\n  <span class=\"c1\"># Team standards<\/span>\n  <span class=\"na\">default_model<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gpt-4o-mini<\/span>\n  <span class=\"na\">max_tokens<\/span><span class=\"pi\">:<\/span> <span class=\"m\">4000<\/span>\n\n<span class=\"c1\"># Documentation<\/span>\n<span class=\"c1\"># See: wiki\/goose-setup.md for installation instructions<\/span>\n<span class=\"c1\"># See: wiki\/goose-workflows.md for common workflows<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n<p><strong>2. Setup script for team members:<\/strong><\/p>\n\n<p><code>scripts\/setup-goose.sh<\/code>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\">#!\/bin\/bash<\/span>\n<span class=\"c\"># goose Team Setup Script<\/span>\n\n<span class=\"nb\">set<\/span> <span class=\"nt\">-e<\/span>\n\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\ud83e\udda2 Setting up goose for team use...\"<\/span>\n\n<span class=\"c\"># Detect OS and set config path<\/span>\n<span class=\"k\">if<\/span> <span class=\"o\">[[<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$OSTYPE<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"darwin\"<\/span><span class=\"k\">*<\/span> <span class=\"o\">]]<\/span> <span class=\"o\">||<\/span> <span class=\"o\">[[<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$OSTYPE<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"linux-gnu\"<\/span><span class=\"k\">*<\/span> <span class=\"o\">]]<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nv\">CONFIG_DIR<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"<\/span><span class=\"nv\">$HOME<\/span><span class=\"s2\">\/.config\/goose\"<\/span>\n<span class=\"k\">elif<\/span> <span class=\"o\">[[<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$OSTYPE<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"msys\"<\/span> <span class=\"o\">]]<\/span> <span class=\"o\">||<\/span> <span class=\"o\">[[<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$OSTYPE<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"win32\"<\/span> <span class=\"o\">]]<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nv\">CONFIG_DIR<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"<\/span><span class=\"nv\">$APPDATA<\/span><span class=\"s2\">\/goose\"<\/span>\n<span class=\"k\">else\n    <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"Unsupported OS: <\/span><span class=\"nv\">$OSTYPE<\/span><span class=\"s2\">\"<\/span>\n    <span class=\"nb\">exit <\/span>1\n<span class=\"k\">fi<\/span>\n\n<span class=\"c\"># Create config directory if it doesn't exist<\/span>\n<span class=\"nb\">mkdir<\/span> <span class=\"nt\">-p<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$CONFIG_DIR<\/span><span class=\"s2\">\"<\/span>\n\n<span class=\"c\"># Copy team configuration<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\ud83d\udccb Copying team configuration...\"<\/span>\n<span class=\"nb\">cp<\/span> .goose\/team-config.yaml <span class=\"s2\">\"<\/span><span class=\"nv\">$CONFIG_DIR<\/span><span class=\"s2\">\/config.yaml\"<\/span>\n\n<span class=\"c\"># Check for required environment variables<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\ud83d\udd11 Checking environment variables...\"<\/span>\n<span class=\"nv\">required_vars<\/span><span class=\"o\">=(<\/span><span class=\"s2\">\"OPENAI_API_KEY\"<\/span> <span class=\"s2\">\"GITHUB_TOKEN\"<\/span> <span class=\"s2\">\"COMPANY_API_KEY\"<\/span><span class=\"o\">)<\/span>\n<span class=\"nv\">missing_vars<\/span><span class=\"o\">=()<\/span>\n\n<span class=\"k\">for <\/span>var <span class=\"k\">in<\/span> <span class=\"s2\">\"<\/span><span class=\"k\">${<\/span><span class=\"nv\">required_vars<\/span><span class=\"p\">[@]<\/span><span class=\"k\">}<\/span><span class=\"s2\">\"<\/span><span class=\"p\">;<\/span> <span class=\"k\">do\n    if<\/span> <span class=\"o\">[<\/span> <span class=\"nt\">-z<\/span> <span class=\"s2\">\"<\/span><span class=\"k\">${<\/span><span class=\"p\">!var<\/span><span class=\"k\">}<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">]<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n        <\/span>missing_vars+<span class=\"o\">=(<\/span><span class=\"s2\">\"<\/span><span class=\"nv\">$var<\/span><span class=\"s2\">\"<\/span><span class=\"o\">)<\/span>\n    <span class=\"k\">fi\ndone\n\nif<\/span> <span class=\"o\">[<\/span> <span class=\"k\">${#<\/span><span class=\"nv\">missing_vars<\/span><span class=\"p\">[@]<\/span><span class=\"k\">}<\/span> <span class=\"nt\">-gt<\/span> 0 <span class=\"o\">]<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u26a0\ufe0f  Warning: Missing environment variables:\"<\/span>\n    <span class=\"k\">for <\/span>var <span class=\"k\">in<\/span> <span class=\"s2\">\"<\/span><span class=\"k\">${<\/span><span class=\"nv\">missing_vars<\/span><span class=\"p\">[@]<\/span><span class=\"k\">}<\/span><span class=\"s2\">\"<\/span><span class=\"p\">;<\/span> <span class=\"k\">do\n        <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"  - <\/span><span class=\"nv\">$var<\/span><span class=\"s2\">\"<\/span>\n    <span class=\"k\">done\n    <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"\"<\/span>\n    <span class=\"nb\">echo<\/span> <span class=\"s2\">\"Set these in your ~\/.bashrc or ~\/.zshrc:\"<\/span>\n    <span class=\"k\">for <\/span>var <span class=\"k\">in<\/span> <span class=\"s2\">\"<\/span><span class=\"k\">${<\/span><span class=\"nv\">missing_vars<\/span><span class=\"p\">[@]<\/span><span class=\"k\">}<\/span><span class=\"s2\">\"<\/span><span class=\"p\">;<\/span> <span class=\"k\">do\n        <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"  export <\/span><span class=\"nv\">$var<\/span><span class=\"s2\">='your-key-here'\"<\/span>\n    <span class=\"k\">done\nfi<\/span>\n\n<span class=\"c\"># Install required tools<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\ud83d\udce6 Installing required tools...\"<\/span>\n<span class=\"nb\">command<\/span> <span class=\"nt\">-v<\/span> uv <span class=\"o\">&gt;<\/span>\/dev\/null 2&gt;&amp;1 <span class=\"o\">||<\/span> <span class=\"o\">{<\/span>\n    <span class=\"nb\">echo<\/span> <span class=\"s2\">\"Installing uv...\"<\/span>\n    curl <span class=\"nt\">-LsSf<\/span> https:\/\/astral.sh\/uv\/install.sh | sh\n<span class=\"o\">}<\/span>\n\n<span class=\"nb\">command<\/span> <span class=\"nt\">-v<\/span> npx <span class=\"o\">&gt;<\/span>\/dev\/null 2&gt;&amp;1 <span class=\"o\">||<\/span> <span class=\"o\">{<\/span>\n    <span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u26a0\ufe0f  npx not found. Please install Node.js.\"<\/span>\n<span class=\"o\">}<\/span>\n\n<span class=\"c\"># Verify goose installation<\/span>\n<span class=\"k\">if <\/span><span class=\"nb\">command<\/span> <span class=\"nt\">-v<\/span> goose <span class=\"o\">&gt;<\/span>\/dev\/null 2&gt;&amp;1<span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u2705 goose is installed: <\/span><span class=\"si\">$(<\/span>goose <span class=\"nt\">--version<\/span><span class=\"si\">)<\/span><span class=\"s2\">\"<\/span>\n<span class=\"k\">else\n    <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u26a0\ufe0f  goose is not installed. Install from: https:\/\/block.github.io\/goose\"<\/span>\n<span class=\"k\">fi\n\n<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u2705 Team configuration setup complete!\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"Next steps:\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"1. Ensure all environment variables are set\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"2. Run 'goose session' to verify setup\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"3. See wiki\/goose-workflows.md for common workflows\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>3. Documentation:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code># goose Team Setup\n\n## Quick Start\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<ol>\n<li>Run the setup script:\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>   .\/scripts\/setup-goose.sh\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<ol>\n<li>Set required environment variables in <code>~\/.bashrc<\/code> or <code>~\/.zshrc<\/code>:\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>   <span class=\"nb\">export <\/span><span class=\"nv\">OPENAI_API_KEY<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"sk-...\"<\/span>\n   <span class=\"nb\">export <\/span><span class=\"nv\">GITHUB_TOKEN<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"ghp_...\"<\/span>\n   <span class=\"nb\">export <\/span><span class=\"nv\">COMPANY_API_KEY<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"...\"<\/span>\n   <span class=\"nb\">export <\/span><span class=\"nv\">JIRA_URL<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"https:\/\/company.atlassian.net\"<\/span>\n   <span class=\"nb\">export <\/span><span class=\"nv\">JIRA_EMAIL<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"you@company.com\"<\/span>\n   <span class=\"nb\">export <\/span><span class=\"nv\">JIRA_API_TOKEN<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"...\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<ol>\n<li>Reload your shell:\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>   <span class=\"nb\">source<\/span> ~\/.bashrc  <span class=\"c\"># or ~\/.zshrc<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<ol>\n<li>Test the setup:\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>   goose session\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Configuration Changes\n<\/h4>\n\n<p>The team configuration is stored in <code>.goose\/team-config.yaml<\/code>.<\/p>\n\n<p>To propose changes:<\/p>\n\n<ol>\n<li>Update <code>.goose\/team-config.yaml<\/code>\n<\/li>\n<li>Test locally<\/li>\n<li>Submit PR with description of changes<\/li>\n<li>Tag <code>@platform-team<\/code> for review<\/li>\n<\/ol>\n\n<h4>\n  \n  \n  Getting API Keys\n<\/h4>\n\n<ul>\n<li>\n<strong>OpenAI<\/strong>: Get from <a href=\"https:\/\/platform.openai.com\" rel=\"noopener noreferrer\">platform.openai.com<\/a>\n<\/li>\n<li>\n<strong>GitHub<\/strong>: Generate at <a href=\"https:\/\/github.com\/settings\/tokens\" rel=\"noopener noreferrer\">github.com\/settings\/tokens<\/a>\n<\/li>\n<li>\n<strong>Company API<\/strong>: Request from #platform-team Slack channel<\/li>\n<li>\n<strong>Jira<\/strong>: Generate at <a href=\"https:\/\/company.atlassian.net\/secure\/ViewProfile.jspa\" rel=\"noopener noreferrer\">company.atlassian.net\/secure\/ViewProfile.jspa<\/a>\n<\/li>\n<\/ul>\n\n<h5>\n  \n  \n  Troubleshooting\n<\/h5>\n\n<p>See <a href=\"https:\/\/block.github.io\/goose\/docs\/troubleshooting\/\" rel=\"noopener noreferrer\">goose-troubleshooting.md<\/a><\/p>\n\n<p><strong>Pros<\/strong><\/p>\n\n<ul>\n<li>Simple to implement<\/li>\n<li>Everyone uses same configuration<\/li>\n<li>Easy to update (just update file and re-run script)<\/li>\n<li>Good for small team<\/li>\n<\/ul>\n\n<p><strong>Cons<\/strong><\/p>\n\n<ul>\n<li>No customization per user<\/li>\n<li> Harder to manage different roles\/permissions<\/li>\n<li> All extensions enabled for everyone<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Strategy 2: Per-Environment Configurations\n<\/h3>\n\n<p><strong>Best for<\/strong>: Medium teams (15-50 people), multiple projects, different roles<br>\n<strong>How it works<\/strong>: Maintain separate configurations for different environments or roles (backend, frontend, DevOps, etc.).<\/p>\n\n<p><strong>Implementation<\/strong><br>\n<strong>Configuration files:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>.goose\/\n\u251c\u2500\u2500 base-config.yaml          # Common settings\n\u251c\u2500\u2500 backend-config.yaml       # Backend developers\n\u251c\u2500\u2500 frontend-config.yaml      # Frontend developers\n\u251c\u2500\u2500 devops-config.yaml        # DevOps\/SRE\n\u2514\u2500\u2500 qa-config.yaml            # QA engineers\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>base-config.yaml<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"c1\"># Shared by all team members<\/span>\n<span class=\"na\">providers<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">openai<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">model<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gpt-4o-mini<\/span>\n    <span class=\"na\">api_key_env<\/span><span class=\"pi\">:<\/span> <span class=\"s\">OPENAI_API_KEY<\/span>\n\n<span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">developer<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">enabled<\/span><span class=\"pi\">:<\/span> <span class=\"kc\">true<\/span>\n\n  <span class=\"na\">github<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">npx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">-y\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">@modelcontextprotocol\/server-github\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">GITHUB_TOKEN<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${GITHUB_TOKEN}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>frontend-config.yaml<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"c1\"># Frontend-specific extensions<\/span>\n<span class=\"na\">extends<\/span><span class=\"pi\">:<\/span> <span class=\"s\">base-config.yaml<\/span>\n\n<span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">figma<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">npx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">-y\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">mcp-figma\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">FIGMA_TOKEN<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${FIGMA_TOKEN}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n\n  <span class=\"na\">storybook<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uvx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">mcp-storybook\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>devops-config.yaml<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"c1\"># DevOps-specific extensions<\/span>\n<span class=\"na\">extends<\/span><span class=\"pi\">:<\/span> <span class=\"s\">base-config.yaml<\/span>\n\n<span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">aws<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uvx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">mcp-aws\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">AWS_REGION<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${AWS_REGION}\"<\/span>\n      <span class=\"na\">AWS_PROFILE<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${AWS_PROFILE}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">600<\/span>\n\n  <span class=\"na\">kubernetes<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uvx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">mcp-kubernetes\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">KUBECONFIG<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${KUBECONFIG}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n\n  <span class=\"na\">datadog<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uvx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">mcp-datadog\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">DD_API_KEY<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${DD_API_KEY}\"<\/span>\n      <span class=\"na\">DD_APP_KEY<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${DD_APP_KEY}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Setup script with role selection<\/strong><br>\n<code>scripts\/setup-goose.sh<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\">#!\/bin\/bash<\/span>\n\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\ud83e\udda2 goose Team Setup\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"Select your role:\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"1) Backend Developer\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"2) Frontend Developer\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"3) DevOps\/SRE\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"4) QA Engineer\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\"<\/span>\n<span class=\"nb\">read<\/span> <span class=\"nt\">-p<\/span> <span class=\"s2\">\"Enter choice [1-4]: \"<\/span> choice\n\n<span class=\"k\">case<\/span> <span class=\"nv\">$choice<\/span> <span class=\"k\">in\n    <\/span>1<span class=\"p\">)<\/span>\n        <span class=\"nv\">CONFIG_FILE<\/span><span class=\"o\">=<\/span><span class=\"s2\">\".goose\/backend-config.yaml\"<\/span>\n        <span class=\"nv\">ROLE<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"Backend\"<\/span>\n        <span class=\"p\">;;<\/span>\n    2<span class=\"p\">)<\/span>\n        <span class=\"nv\">CONFIG_FILE<\/span><span class=\"o\">=<\/span><span class=\"s2\">\".goose\/frontend-config.yaml\"<\/span>\n        <span class=\"nv\">ROLE<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"Frontend\"<\/span>\n        <span class=\"p\">;;<\/span>\n    3<span class=\"p\">)<\/span>\n        <span class=\"nv\">CONFIG_FILE<\/span><span class=\"o\">=<\/span><span class=\"s2\">\".goose\/devops-config.yaml\"<\/span>\n        <span class=\"nv\">ROLE<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"DevOps\"<\/span>\n        <span class=\"p\">;;<\/span>\n    4<span class=\"p\">)<\/span>\n        <span class=\"nv\">CONFIG_FILE<\/span><span class=\"o\">=<\/span><span class=\"s2\">\".goose\/qa-config.yaml\"<\/span>\n        <span class=\"nv\">ROLE<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"QA\"<\/span>\n        <span class=\"p\">;;<\/span>\n    <span class=\"k\">*<\/span><span class=\"p\">)<\/span>\n        <span class=\"nb\">echo<\/span> <span class=\"s2\">\"Invalid choice\"<\/span>\n        <span class=\"nb\">exit <\/span>1\n        <span class=\"p\">;;<\/span>\n<span class=\"k\">esac<\/span>\n\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\ud83d\udccb Setting up <\/span><span class=\"nv\">$ROLE<\/span><span class=\"s2\"> configuration...\"<\/span>\n\n<span class=\"c\"># Detect OS and set config path<\/span>\n<span class=\"k\">if<\/span> <span class=\"o\">[[<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$OSTYPE<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"darwin\"<\/span><span class=\"k\">*<\/span> <span class=\"o\">]]<\/span> <span class=\"o\">||<\/span> <span class=\"o\">[[<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$OSTYPE<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"linux-gnu\"<\/span><span class=\"k\">*<\/span> <span class=\"o\">]]<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nv\">CONFIG_DIR<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"<\/span><span class=\"nv\">$HOME<\/span><span class=\"s2\">\/.config\/goose\"<\/span>\n<span class=\"k\">elif<\/span> <span class=\"o\">[[<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$OSTYPE<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"msys\"<\/span> <span class=\"o\">]]<\/span> <span class=\"o\">||<\/span> <span class=\"o\">[[<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$OSTYPE<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"win32\"<\/span> <span class=\"o\">]]<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nv\">CONFIG_DIR<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"<\/span><span class=\"nv\">$APPDATA<\/span><span class=\"s2\">\/goose\"<\/span>\n<span class=\"k\">fi\n\n<\/span><span class=\"nb\">mkdir<\/span> <span class=\"nt\">-p<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$CONFIG_DIR<\/span><span class=\"s2\">\"<\/span>\n<span class=\"nb\">cp<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$CONFIG_FILE<\/span><span class=\"s2\">\"<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$CONFIG_DIR<\/span><span class=\"s2\">\/config.yaml\"<\/span>\n\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u2705 Configuration installed!\"<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\ud83d\udcda See docs\/goose-<\/span><span class=\"nv\">$ROLE<\/span><span class=\"s2\">-guide.md for role-specific workflows\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Pros<\/strong><\/p>\n\n<ul>\n<li>Customized per role<\/li>\n<li>Only install needed extensions<\/li>\n<li>Role-specific documentation<\/li>\n<li>Scales better than single config<\/li>\n<\/ul>\n\n<p><strong>Cons<\/strong><\/p>\n\n<ul>\n<li>More maintenance overhead<\/li>\n<li>Configuration drift between roles<\/li>\n<li>Need to manage multiple files<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Strategy 3: Team Templates\n<\/h3>\n\n<p><strong>Best for<\/strong>: Large teams (50+ people), enterprises, strict compliance requirements<\/p>\n\n<p><strong>How it works<\/strong>: Use a configuration management tool to generate and distribute configurations dynamically.<\/p>\n\n<p><strong>Implementation<\/strong><br>\n<strong>Using a configuration generator<\/strong>:<br>\n<code>scripts\/generate-config.py<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\">#!\/usr\/bin\/env python3\n<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\nGenerate goose configuration based on user role and permissions\n<\/span><span class=\"sh\">\"\"\"<\/span>\n\n<span class=\"kn\">import<\/span> <span class=\"n\">os<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">yaml<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">argparse<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">pathlib<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Path<\/span>\n\n<span class=\"c1\"># Base configuration template\n<\/span><span class=\"n\">BASE_CONFIG<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">providers<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">openai<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">model<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">gpt-4o-mini<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">api_key_env<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">OPENAI_API_KEY<\/span><span class=\"sh\">'<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">extensions<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">developer<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">enabled<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"bp\">True<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\"># Role-specific extensions\n<\/span><span class=\"n\">ROLE_EXTENSIONS<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">backend<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">postgres<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">type<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">stdio<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">command<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">uvx<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">args<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">mcp-postgres<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">env<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">DATABASE_URL<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${DATABASE_URL}<\/span><span class=\"sh\">'<\/span><span class=\"p\">},<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">300<\/span>\n        <span class=\"p\">},<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">redis<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">type<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">stdio<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">command<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">uvx<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">args<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">mcp-redis<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">env<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">REDIS_URL<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${REDIS_URL}<\/span><span class=\"sh\">'<\/span><span class=\"p\">},<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">300<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">frontend<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">figma<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">type<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">stdio<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">command<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">npx<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">args<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">-y<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">mcp-figma<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">env<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">FIGMA_TOKEN<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${FIGMA_TOKEN}<\/span><span class=\"sh\">'<\/span><span class=\"p\">},<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">300<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">devops<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">aws<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">type<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">stdio<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">command<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">uvx<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">args<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">mcp-aws<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">env<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n                <span class=\"sh\">'<\/span><span class=\"s\">AWS_REGION<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${AWS_REGION}<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">'<\/span><span class=\"s\">AWS_PROFILE<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${AWS_PROFILE}<\/span><span class=\"sh\">'<\/span>\n            <span class=\"p\">},<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">600<\/span>\n        <span class=\"p\">},<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">kubernetes<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">type<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">stdio<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">command<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">uvx<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">args<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">mcp-kubernetes<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">env<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">KUBECONFIG<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${KUBECONFIG}<\/span><span class=\"sh\">'<\/span><span class=\"p\">},<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">300<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\"># Team-wide extensions (everyone gets these)\n<\/span><span class=\"n\">TEAM_EXTENSIONS<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">github<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">type<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">stdio<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">command<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">npx<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">args<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">-y<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">@modelcontextprotocol\/server-github<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">env<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">GITHUB_TOKEN<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${GITHUB_TOKEN}<\/span><span class=\"sh\">'<\/span><span class=\"p\">},<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">300<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">jira<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">type<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">stdio<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">command<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">uvx<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">args<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">mcp-jira<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">env<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">JIRA_URL<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${JIRA_URL}<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">JIRA_EMAIL<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${JIRA_EMAIL}<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">'<\/span><span class=\"s\">JIRA_API_TOKEN<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${JIRA_API_TOKEN}<\/span><span class=\"sh\">'<\/span>\n        <span class=\"p\">},<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">300<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">generate_config<\/span><span class=\"p\">(<\/span><span class=\"n\">role<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">custom_extensions<\/span><span class=\"p\">:<\/span> <span class=\"nb\">list<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Generate configuration for a specific role<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">config<\/span> <span class=\"o\">=<\/span> <span class=\"n\">BASE_CONFIG<\/span><span class=\"p\">.<\/span><span class=\"nf\">copy<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"c1\"># Add team-wide extensions\n<\/span>    <span class=\"n\">config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">extensions<\/span><span class=\"sh\">'<\/span><span class=\"p\">].<\/span><span class=\"nf\">update<\/span><span class=\"p\">(<\/span><span class=\"n\">TEAM_EXTENSIONS<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\"># Add role-specific extensions\n<\/span>    <span class=\"k\">if<\/span> <span class=\"n\">role<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">ROLE_EXTENSIONS<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">extensions<\/span><span class=\"sh\">'<\/span><span class=\"p\">].<\/span><span class=\"nf\">update<\/span><span class=\"p\">(<\/span><span class=\"n\">ROLE_EXTENSIONS<\/span><span class=\"p\">[<\/span><span class=\"n\">role<\/span><span class=\"p\">])<\/span>\n\n    <span class=\"c1\"># Add custom extensions\n<\/span>    <span class=\"k\">if<\/span> <span class=\"n\">custom_extensions<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">for<\/span> <span class=\"n\">ext<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">custom_extensions<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">if<\/span> <span class=\"n\">ext<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">ROLE_EXTENSIONS<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">extensions<\/span><span class=\"sh\">'<\/span><span class=\"p\">].<\/span><span class=\"nf\">update<\/span><span class=\"p\">({<\/span><span class=\"n\">ext<\/span><span class=\"p\">:<\/span> <span class=\"n\">ROLE_EXTENSIONS<\/span><span class=\"p\">[<\/span><span class=\"n\">ext<\/span><span class=\"p\">]})<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"n\">config<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">get_config_path<\/span><span class=\"p\">()<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Path<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Get OS-specific config path<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">if<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"n\">name<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">'<\/span><span class=\"s\">nt<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span>  <span class=\"c1\"># Windows\n<\/span>        <span class=\"k\">return<\/span> <span class=\"nc\">Path<\/span><span class=\"p\">(<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">APPDATA<\/span><span class=\"sh\">'<\/span><span class=\"p\">))<\/span> <span class=\"o\">\/<\/span> <span class=\"sh\">'<\/span><span class=\"s\">goose<\/span><span class=\"sh\">'<\/span> <span class=\"o\">\/<\/span> <span class=\"sh\">'<\/span><span class=\"s\">config.yaml<\/span><span class=\"sh\">'<\/span>\n    <span class=\"k\">else<\/span><span class=\"p\">:<\/span>  <span class=\"c1\"># Linux\/macOS\n<\/span>        <span class=\"k\">return<\/span> <span class=\"n\">Path<\/span><span class=\"p\">.<\/span><span class=\"nf\">home<\/span><span class=\"p\">()<\/span> <span class=\"o\">\/<\/span> <span class=\"sh\">'<\/span><span class=\"s\">.config<\/span><span class=\"sh\">'<\/span> <span class=\"o\">\/<\/span> <span class=\"sh\">'<\/span><span class=\"s\">goose<\/span><span class=\"sh\">'<\/span> <span class=\"o\">\/<\/span> <span class=\"sh\">'<\/span><span class=\"s\">config.yaml<\/span><span class=\"sh\">'<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">main<\/span><span class=\"p\">():<\/span>\n    <span class=\"n\">parser<\/span> <span class=\"o\">=<\/span> <span class=\"n\">argparse<\/span><span class=\"p\">.<\/span><span class=\"nc\">ArgumentParser<\/span><span class=\"p\">(<\/span><span class=\"n\">description<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">Generate goose team configuration<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">parser<\/span><span class=\"p\">.<\/span><span class=\"nf\">add_argument<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">role<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">choices<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">backend<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">frontend<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">devops<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">qa<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n                       <span class=\"n\">help<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">Your role<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">parser<\/span><span class=\"p\">.<\/span><span class=\"nf\">add_argument<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">--output<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">-o<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">help<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">Output file (default: install to config dir)<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">parser<\/span><span class=\"p\">.<\/span><span class=\"nf\">add_argument<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">--extensions<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">-e<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">nargs<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">+<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n                       <span class=\"n\">help<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">Additional extensions to enable<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">parser<\/span><span class=\"p\">.<\/span><span class=\"nf\">add_argument<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">--dry-run<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">action<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">store_true<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n                       <span class=\"n\">help<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">Print configuration without installing<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">args<\/span> <span class=\"o\">=<\/span> <span class=\"n\">parser<\/span><span class=\"p\">.<\/span><span class=\"nf\">parse_args<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"c1\"># Generate configuration\n<\/span>    <span class=\"n\">config<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">generate_config<\/span><span class=\"p\">(<\/span><span class=\"n\">args<\/span><span class=\"p\">.<\/span><span class=\"n\">role<\/span><span class=\"p\">,<\/span> <span class=\"n\">args<\/span><span class=\"p\">.<\/span><span class=\"n\">extensions<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\"># Convert to YAML\n<\/span>    <span class=\"n\">yaml_config<\/span> <span class=\"o\">=<\/span> <span class=\"n\">yaml<\/span><span class=\"p\">.<\/span><span class=\"nf\">dump<\/span><span class=\"p\">(<\/span><span class=\"n\">config<\/span><span class=\"p\">,<\/span> <span class=\"n\">default_flow_style<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">,<\/span> <span class=\"n\">sort_keys<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"n\">args<\/span><span class=\"p\">.<\/span><span class=\"n\">dry_run<\/span><span class=\"p\">:<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">yaml_config<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span>\n\n    <span class=\"c1\"># Determine output path\n<\/span>    <span class=\"k\">if<\/span> <span class=\"n\">args<\/span><span class=\"p\">.<\/span><span class=\"n\">output<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">output_path<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Path<\/span><span class=\"p\">(<\/span><span class=\"n\">args<\/span><span class=\"p\">.<\/span><span class=\"n\">output<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">output_path<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_config_path<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"c1\"># Create directory if needed\n<\/span>    <span class=\"n\">output_path<\/span><span class=\"p\">.<\/span><span class=\"n\">parent<\/span><span class=\"p\">.<\/span><span class=\"nf\">mkdir<\/span><span class=\"p\">(<\/span><span class=\"n\">parents<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">exist_ok<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\"># Write configuration\n<\/span>    <span class=\"n\">output_path<\/span><span class=\"p\">.<\/span><span class=\"nf\">write_text<\/span><span class=\"p\">(<\/span><span class=\"n\">yaml_config<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\u2705 Configuration generated for role: <\/span><span class=\"si\">{<\/span><span class=\"n\">args<\/span><span class=\"p\">.<\/span><span class=\"n\">role<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\ud83d\udcdd Written to: <\/span><span class=\"si\">{<\/span><span class=\"n\">output_path<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"se\">\\n<\/span><span class=\"s\">Next steps:<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">1. Set required environment variables<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">2. Run <\/span><span class=\"sh\">'<\/span><span class=\"s\">goose session<\/span><span class=\"sh\">'<\/span><span class=\"s\"> to verify setup<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">3. See docs\/goose-<\/span><span class=\"si\">{<\/span><span class=\"n\">args<\/span><span class=\"p\">.<\/span><span class=\"n\">role<\/span><span class=\"si\">}<\/span><span class=\"s\">-guide.md for workflows<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"n\">__name__<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">'<\/span><span class=\"s\">__main__<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span>\n    <span class=\"nf\">main<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Usage<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Generate backend developer config<\/span>\npython scripts\/generate-config.py backend\n\n<span class=\"c\"># Generate with additional extensions<\/span>\npython scripts\/generate-config.py frontend <span class=\"nt\">--extensions<\/span> postgres redis\n\n<span class=\"c\"># Preview without installing<\/span>\npython scripts\/generate-config.py devops <span class=\"nt\">--dry-run<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Pros<\/strong><\/p>\n\n<ul>\n<li>Highly customizable<\/li>\n<li>Centralized control<\/li>\n<li>Audit trail of configurations<\/li>\n<li>Easy to enforce policies<\/li>\n<li>Can integrate with identity management<\/li>\n<\/ul>\n\n<p><strong>Cons<\/strong><\/p>\n\n<ul>\n<li>Most complex to set up<\/li>\n<li>Requires maintenance<\/li>\n<li>Overkill for small teams<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Managing API Keys and Secrets\n<\/h2>\n\n<p><strong>Critical<\/strong>: Never commit API keys to version control!<\/p>\n\n<h3>\n  \n  \n  Recommended Approach: Environment Variables\n<\/h3>\n\n<p><strong>1. Create a template file<\/strong><br>\n<code>.env.template<\/code> <strong>(safe to commit)<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># goose Environment Variables<\/span>\n<span class=\"c\"># Copy to .env and fill in your values<\/span>\n\n<span class=\"c\"># OpenAI<\/span>\n<span class=\"nv\">OPENAI_API_KEY<\/span><span class=\"o\">=<\/span>sk-...\n\n<span class=\"c\"># GitHub<\/span>\n<span class=\"nv\">GITHUB_TOKEN<\/span><span class=\"o\">=<\/span>ghp_...\n\n<span class=\"c\"># Company API<\/span>\n<span class=\"nv\">COMPANY_API_KEY<\/span><span class=\"o\">=<\/span>...\n\n<span class=\"c\"># Jira<\/span>\n<span class=\"nv\">JIRA_URL<\/span><span class=\"o\">=<\/span>https:\/\/company.atlassian.net\n<span class=\"nv\">JIRA_EMAIL<\/span><span class=\"o\">=<\/span>you@company.com\n<span class=\"nv\">JIRA_API_TOKEN<\/span><span class=\"o\">=<\/span>...\n\n<span class=\"c\"># AWS (for DevOps)<\/span>\n<span class=\"nv\">AWS_REGION<\/span><span class=\"o\">=<\/span>us-east-1\n<span class=\"nv\">AWS_PROFILE<\/span><span class=\"o\">=<\/span>default\n\n<span class=\"c\"># Database (for Backend)<\/span>\n<span class=\"nv\">DATABASE_URL<\/span><span class=\"o\">=<\/span>postgresql:\/\/localhost:5432\/dev\n<span class=\"nv\">REDIS_URL<\/span><span class=\"o\">=<\/span>redis:\/\/localhost:6379\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<ol>\n<li>\n<strong>Add to<\/strong> <code>.gitignore<\/code>\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code># goose secrets\n.env\n*.key\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<ol>\n<li>\n<strong>Setup script to load environment<\/strong>\n<code>scripts\/load-goose-env.sh<\/code>\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\">#!\/bin\/bash<\/span>\n<span class=\"c\"># Source this file to load goose environment variables<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"o\">[<\/span> <span class=\"nt\">-f<\/span> .env <span class=\"o\">]<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nb\">export<\/span> <span class=\"si\">$(<\/span><span class=\"nb\">cat<\/span> .env | <span class=\"nb\">grep<\/span> <span class=\"nt\">-v<\/span> <span class=\"s1\">'^#'<\/span> | xargs<span class=\"si\">)<\/span>\n    <span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u2705 Environment variables loaded from .env\"<\/span>\n<span class=\"k\">else\n    <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u26a0\ufe0f  .env file not found\"<\/span>\n    <span class=\"nb\">echo<\/span> <span class=\"s2\">\"Copy .env.template to .env and fill in your values\"<\/span>\n    <span class=\"nb\">exit <\/span>1\n<span class=\"k\">fi<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Usage<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code># Load environment before using goose\nsource scripts\/load-goose-env.sh\ngoose session\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Alternative: Secret Management Services\n<\/h3>\n\n<p>For enterprises, use a dedicated secret management service:<br>\n<strong>1. Using 1Password CLI<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Store secret<\/span>\nop item create <span class=\"nt\">--category<\/span><span class=\"o\">=<\/span>login <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--title<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"goose OpenAI Key\"<\/span> <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--vault<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"Engineering\"<\/span> <span class=\"se\">\\<\/span>\n  <span class=\"s2\">\"password=sk-...\"<\/span>\n\n<span class=\"c\"># Retrieve in script<\/span>\n<span class=\"nb\">export <\/span><span class=\"nv\">OPENAI_API_KEY<\/span><span class=\"o\">=<\/span><span class=\"si\">$(<\/span>op <span class=\"nb\">read<\/span> <span class=\"s2\">\"op:\/\/Engineering\/goose OpenAI Key\/password\"<\/span><span class=\"si\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>2. Using AWS Secrets Manager<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Store secret<\/span>\naws secretsmanager create-secret <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--name<\/span> goose\/openai-key <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--secret-string<\/span> <span class=\"s2\">\"sk-...\"<\/span>\n\n<span class=\"c\"># Retrieve in script<\/span>\n<span class=\"nb\">export <\/span><span class=\"nv\">OPENAI_API_KEY<\/span><span class=\"o\">=<\/span><span class=\"si\">$(<\/span>aws secretsmanager get-secret-value <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--secret-id<\/span> goose\/openai-key <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--query<\/span> SecretString <span class=\"se\">\\<\/span>\n  <span class=\"nt\">--output<\/span> text<span class=\"si\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>3. Using HashiCorp Vault<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Store secret<\/span>\nvault kv put secret\/goose\/openai <span class=\"nv\">key<\/span><span class=\"o\">=<\/span>sk-...\n\n<span class=\"c\"># Retrieve in script<\/span>\n<span class=\"nb\">export <\/span><span class=\"nv\">OPENAI_API_KEY<\/span><span class=\"o\">=<\/span><span class=\"si\">$(<\/span>vault kv get <span class=\"nt\">-field<\/span><span class=\"o\">=<\/span>key secret\/goose\/openai<span class=\"si\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Version Control Best Practices\n<\/h2>\n\n<h3>\n  \n  \n  What to Commit\n<\/h3>\n\n<p><strong>DO commit<\/strong><\/p>\n\n<ul>\n<li>Base configuration templates<\/li>\n<li>Setup scripts<\/li>\n<li>Documentation<\/li>\n<li><code>.env.template files<\/code><\/li>\n<li>Test configurations (with dummy values)<\/li>\n<\/ul>\n\n<p><strong>DON'T commit<\/strong><\/p>\n\n<ul>\n<li>Personal API keys<\/li>\n<li>\n<code>.env<\/code> files with real values<\/li>\n<li>Individual user configurations<\/li>\n<li>Logs or session data<\/li>\n<\/ul>\n\n<p><code>.gitignore<\/code> <strong>Template<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code># goose\n.env\n.env.local\n*.key\n*.pem\n\n# OS-specific\n.DS_Store\nThumbs.db\n\n# Editor\n.vscode\/\n.idea\/\n*.swp\n*.swo\n\n# Logs\n*.log\ngoose-*.log\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Configuration Versioning\n<\/h3>\n\n<p>Track configuration changes with meaningful commit messages:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Good commit messages<\/span>\ngit commit <span class=\"nt\">-m<\/span> <span class=\"s2\">\"feat(goose): add PostgreSQL extension for backend team\"<\/span>\ngit commit <span class=\"nt\">-m<\/span> <span class=\"s2\">\"fix(goose): update GitHub token environment variable name\"<\/span>\ngit commit <span class=\"nt\">-m<\/span> <span class=\"s2\">\"docs(goose): add troubleshooting guide for extension timeouts\"<\/span>\n\n<span class=\"c\"># Bad commit messages<\/span>\ngit commit <span class=\"nt\">-m<\/span> <span class=\"s2\">\"update config\"<\/span>\ngit commit <span class=\"nt\">-m<\/span> <span class=\"s2\">\"fix\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Shared Extensions and Tooling\n<\/h3>\n\n<p>Create custom extensions for team-specific needs.<\/p>\n\n<h4>\n  \n  \n  Example: Company API Extension\n<\/h4>\n\n<p><strong>Scenario<\/strong>: Your team frequently interacts with internal APIs. Create an MCP server for common operations.<\/p>\n\n<p><code>company-api-mcp\/src\/company_api\/server.py<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">mcp.server.fastmcp<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">FastMCP<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">os<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">requests<\/span>\n\n<span class=\"n\">mcp<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">FastMCP<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">company-api<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">get_user<\/span><span class=\"p\">(<\/span><span class=\"n\">user_id<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Get user details from company API<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">api_key<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">COMPANY_API_KEY<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span>\n        <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/api.company.com\/users\/<\/span><span class=\"si\">{<\/span><span class=\"n\">user_id<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Authorization<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Bearer <\/span><span class=\"si\">{<\/span><span class=\"n\">api_key<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">}<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">json<\/span><span class=\"p\">()<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">create_deployment<\/span><span class=\"p\">(<\/span><span class=\"n\">service<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">version<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">environment<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Create a new deployment<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">api_key<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">COMPANY_API_KEY<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"nf\">post<\/span><span class=\"p\">(<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/api.company.com\/deployments<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Authorization<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Bearer <\/span><span class=\"si\">{<\/span><span class=\"n\">api_key<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">},<\/span>\n        <span class=\"n\">json<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">service<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">service<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">version<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">version<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">environment<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">environment<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">json<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Publish internally<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Build and publish to internal PyPI<\/span>\nuv build\nuv publish <span class=\"nt\">--repository<\/span> internal-pypi\n\n<span class=\"c\"># Team members install with<\/span>\nuvx <span class=\"nt\">--from<\/span> internal-pypi company-api-mcp\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Add to team configuration<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">company_api<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uvx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">--from\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">internal-pypi\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">company-api-mcp\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">COMPANY_API_KEY<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${COMPANY_API_KEY}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Creating Team Workflows\n<\/h3>\n\n<p>Document common workflows so everyone uses goose consistently.<\/p>\n\n<h4>\n  \n  \n  Workflow Documentation Template\n<\/h4>\n\n<p><code>docs\/workflows\/code-review.md<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code><span class=\"gh\"># Workflow: Code Review with goose<\/span>\n\n<span class=\"gu\">## Objective<\/span>\nUse goose to perform initial code review before requesting human review.\n\n<span class=\"gu\">## Steps<\/span>\n<span class=\"p\">\n1.<\/span> <span class=\"gs\">**Check out the PR branch**<\/span>\n   git checkout feature\/new-feature\n<span class=\"p\">\n2.<\/span> <span class=\"gs\">**Start goose session**<\/span>\n   cd project-root\n   goose session\n<span class=\"p\">3.<\/span> <span class=\"gs\">**Request code review**<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Review the changes in this branch compared to main. Focus on:<\/p>\n\n<ul>\n<li>Code quality and readability<\/li>\n<li>Potential bugs or edge cases<\/li>\n<li>Security vulnerabilities<\/li>\n<li>Performance issues<\/li>\n<li>Test coverage<\/li>\n<\/ul>\n\n<p>Provide specific suggestions with file and line numbers.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>4. **Address feedback**\n   - Fix identified issues\n   - Add suggested tests\n   - Improve code based on recommendations\n\n5. **Re-review** (repeat step 3)\n\n6. **Request human review** once goose review is clean\n\n## Tips\n\n- Use \"explain this code\" for complex logic\n- Ask \"what tests should I add?\"\n- Request \"suggest performance improvements\"\n\n## Example Session\n\n\\`\\`\\`\nYou: Review the changes in src\/api\/users.py\n\ngoose: I've reviewed the file. Here are my findings:\n\n1. Line 45: Missing input validation for email parameter\n2. Line 67: SQL injection vulnerability - use parameterized query\n3. Line 89: Consider adding error handling for database connection\n...\n\\`\\`\\`\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Common Workflow Library\n<\/h4>\n\n<p>Create a library of documented workflows:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>docs\/workflows\/\n\u251c\u2500\u2500 code-review.md\n\u251c\u2500\u2500 debugging.md\n\u251c\u2500\u2500 refactoring.md\n\u251c\u2500\u2500 documentation.md\n\u251c\u2500\u2500 test-writing.md\n\u2514\u2500\u2500 deployment.md\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Onboarding New Team Members\n<\/h3>\n\n<p>Create a smooth onboarding experience.<\/p>\n\n<h4>\n  \n  \n  Onboarding Checklist\n<\/h4>\n\n<p><code>docs\/onboarding-checklist.md<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code><span class=\"gh\"># goose Onboarding Checklist<\/span>\n\nWelcome! Follow these steps to get goose set up.\n\n<span class=\"gu\">## Prerequisites<\/span>\n<span class=\"p\">-<\/span> <span class=\"p\">[<\/span><span class=\"nv\"> ] Install goose ([instructions<\/span><span class=\"p\">](<\/span><span class=\"sx\">https:\/\/block.github.io\/goose\/docs\/getting-started\/installation<\/span><span class=\"p\">)<\/span>)\n<span class=\"p\">-<\/span> [ ] Install uv: <span class=\"sb\">`curl -LsSf https:\/\/astral.sh\/uv\/install.sh | sh`<\/span>\n<span class=\"p\">-<\/span> [ ] Install Node.js (for npm extensions)\n\n<span class=\"gu\">## Setup<\/span>\n<span class=\"p\">\n-<\/span> [ ] Clone the team repo\n<span class=\"p\">-<\/span> [ ] Run setup script: <span class=\"sb\">`.\/scripts\/setup-goose.sh`<\/span>\n<span class=\"p\">-<\/span> [ ] Copy <span class=\"sb\">`.env.template`<\/span> to <span class=\"sb\">`.env`<\/span>\n<span class=\"p\">-<\/span> [ ] Get API keys:\n<span class=\"p\">  -<\/span> [ ] OpenAI: [Request from #platform-team]\n<span class=\"p\">  -<\/span> [ ] GitHub: [Generate personal token]\n<span class=\"p\">  -<\/span> [ ] Company API: [Request from #platform-team]\n<span class=\"p\">-<\/span> [ ] Fill in <span class=\"sb\">`.env`<\/span> with your keys\n<span class=\"p\">-<\/span> [ ] Load environment: <span class=\"sb\">`source scripts\/load-goose-env.sh`<\/span>\n<span class=\"p\">-<\/span> [ ] Test setup: <span class=\"sb\">`goose session`<\/span>\n\n<span class=\"gu\">## Learning Resources<\/span>\n<span class=\"p\">\n-<\/span> <span class=\"p\">[<\/span><span class=\"nv\"> ] Read [goose Basics<\/span><span class=\"p\">](<\/span><span class=\"sx\">.\/goose-basics.md<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">-<\/span> <span class=\"p\">[<\/span><span class=\"nv\"> ] Review [Common Workflows<\/span><span class=\"p\">](<\/span><span class=\"sx\">.\/workflows\/<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">-<\/span> <span class=\"p\">[<\/span><span class=\"nv\"> ] Watch [Team Demo Video<\/span><span class=\"p\">](<\/span><span class=\"sx\">link-to-video<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">-<\/span> [ ] Join #goose-users Slack channel\n\n<span class=\"gu\">## First Steps<\/span>\n<span class=\"p\">\n-<\/span> <span class=\"p\">[<\/span><span class=\"nv\"> ] Complete [Tutorial: Code Review<\/span><span class=\"p\">](<\/span><span class=\"sx\">.\/tutorials\/code-review.md<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">-<\/span> [ ] Try workflow: Review your own recent PR\n<span class=\"p\">-<\/span> [ ] Ask questions in #goose-users\n\n<span class=\"gu\">## Getting Help<\/span>\n<span class=\"p\">\n-<\/span> <span class=\"gs\">**Technical issues**<\/span>: #goose-support\n<span class=\"p\">-<\/span> <span class=\"gs\">**API key issues**<\/span>: #platform-team\n<span class=\"p\">-<\/span> <span class=\"gs\">**Workflow questions**<\/span>: #goose-users\n<span class=\"p\">-<\/span> <span class=\"gs\">**Documentation**<\/span>: <span class=\"p\">[<\/span><span class=\"nv\">Team Wiki<\/span><span class=\"p\">](<\/span><span class=\"sx\">wiki\/goose<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">\n---\n<\/span>\n<span class=\"gs\">**Need help?**<\/span> Tag @goose-champions in Discord!\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Onboarding Buddy System\n<\/h4>\n\n<p>Assign experienced goose users as \"buddies\" for new team members:<br>\n<code>scripts\/assign-buddy.sh<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>#!\/bin\/bash\n# Assign a goose buddy to new team member\n\nNEW_MEMBER=$1\nBUDDIES=(\"alice@company.com\" \"bob@company.com\" \"charlie@company.com\")\n\n# Round-robin assignment\nBUDDY=${BUDDIES[$((RANDOM % ${#BUDDIES[@]}))]}\n\necho \"\ud83e\udda2 goose Buddy Assignment\"\necho \"New Member: $NEW_MEMBER\"\necho \"Assigned Buddy: $BUDDY\"\necho \"\"\necho \"Sending notification to Slack...\"\n\n# Send Slack notification (requires Slack webhook)\ncurl -X POST $SLACK_WEBHOOK_URL \\\n  -H 'Content-Type: application\/json' \\\n  -d \"{\n    \\\"text\\\": \\\"\ud83e\udda2 New goose user!\\\",\n    \\\"blocks\\\": [\n      {\n        \\\"type\\\": \\\"section\\\",\n        \\\"text\\\": {\n          \\\"type\\\": \\\"mrkdwn\\\",\n          \\\"text\\\": \\\"*$NEW_MEMBER* is learning goose!\\n\\nBuddy: *$BUDDY*\\n\\nPlease help them get started with:\\n\u2022 Configuration setup\\n\u2022 First workflow\\n\u2022 Answering questions\\\"\n        }\n      }\n    ]\n  }\"\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Troubleshooting Common Issues\n<\/h3>\n\n<p>Document solutions to problems teams frequently encounter.<\/p>\n\n<h4>\n  \n  \n  Issue 1: Extension Not Loading\n<\/h4>\n\n<p><strong>Problem<\/strong>: Extension shows in config but doesn't appear in goose<\/p>\n\n<p><strong>Why This Happens<\/strong><\/p>\n\n<ul>\n<li>The extension executable is not in PATH or doesn't exist<\/li>\n<li>Environment variables required by the extension are not set<\/li>\n<li>The extension command has a typo<\/li>\n<li>Network issues preventing download of npm\/uvx packages<\/li>\n<\/ul>\n\n<p><strong>Solutions<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># 1. Test extension command manually<\/span>\nuvx mcp-postgres  <span class=\"c\"># Should start the server<\/span>\n\n<span class=\"c\"># 2. Check environment variables<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"nv\">$DATABASE_URL<\/span>  <span class=\"c\"># Should output your connection string<\/span>\n\n<span class=\"c\"># 3. Verify goose can find the command<\/span>\nwhich uvx  <span class=\"c\"># Should show path to uvx<\/span>\n\n<span class=\"c\"># 4. Check goose logs<\/span>\n<span class=\"nb\">tail<\/span> <span class=\"nt\">-f<\/span> ~\/.config\/goose\/logs\/goose.log\n\n<span class=\"c\"># 5. Test with MCP Inspector<\/span>\nmcp dev path\/to\/extension\/server.py\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Prevention<\/strong><\/p>\n\n<ul>\n<li>Add extension verification to setup script<\/li>\n<li>Document all required environment variables<\/li>\n<li>Test extensions before adding to team config<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Issue 2: API Rate Limits\n<\/h4>\n\n<p><strong>Problem<\/strong>: goose stops working with \"rate limit exceeded\" errors<\/p>\n\n<p><strong>Why This Happens<\/strong><\/p>\n\n<ul>\n<li>Too many requests in a short time period<\/li>\n<li>Using expensive models for simple tasks<\/li>\n<li>Multiple team members sharing one API key<\/li>\n<li>Automated processes making frequent calls<\/li>\n<\/ul>\n\n<p><strong>Solutions<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"c1\"># Use tiered model approach in config<\/span>\n<span class=\"na\">providers<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">openai<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">model<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gpt-4o-mini<\/span>  <span class=\"c1\"># Default to cheaper model<\/span>\n    <span class=\"na\">api_key_env<\/span><span class=\"pi\">:<\/span> <span class=\"s\">OPENAI_API_KEY<\/span>\n\n  <span class=\"na\">openai_premium<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">model<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gpt-4o<\/span>  <span class=\"c1\"># Premium model for complex tasks<\/span>\n    <span class=\"na\">api_key_env<\/span><span class=\"pi\">:<\/span> <span class=\"s\">OPENAI_API_KEY<\/span>\n\n<span class=\"c1\"># Tell users when to use premium model<\/span>\n<span class=\"na\">preferences<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">model_selection_guide<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">|<\/span>\n    <span class=\"s\">Use gpt-4o-mini (default) for:<\/span>\n    <span class=\"s\">- Code review<\/span>\n    <span class=\"s\">- Documentation<\/span>\n    <span class=\"s\">- Simple refactoring<\/span>\n\n    <span class=\"s\">Use gpt-4o (premium) for:<\/span>\n    <span class=\"s\">- Complex architecture decisions<\/span>\n    <span class=\"s\">- Large-scale refactoring<\/span>\n    <span class=\"s\">- Critical debugging<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Prevention<\/strong><\/p>\n\n<ul>\n<li>Use separate API keys per team member<\/li>\n<li>Set up billing alerts<\/li>\n<li>Monitor usage via OpenAI dashboard<\/li>\n<li>Educate team on model selection<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Issue 3: Configuration Drift\n<\/h4>\n\n<p><strong>Problem<\/strong>: Team members have different configurations causing inconsistent behavior.<\/p>\n\n<p><strong>Why This Happens<\/strong><\/p>\n\n<ul>\n<li>Manual configuration changes not synced<\/li>\n<li>Different team members pulling from outdated sources<\/li>\n<li>Local modifications not documented<\/li>\n<li>No version control for configurations<\/li>\n<\/ul>\n\n<p><strong>Solutions<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># 1. Create configuration validation script<\/span>\n<span class=\"c\">#!\/bin\/bash<\/span>\n<span class=\"c\"># scripts\/validate-config.sh<\/span>\n\n<span class=\"nv\">CONFIG_FILE<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"<\/span><span class=\"nv\">$HOME<\/span><span class=\"s2\">\/.config\/goose\/config.yaml\"<\/span>\n<span class=\"nv\">TEAM_CONFIG<\/span><span class=\"o\">=<\/span><span class=\"s2\">\".goose\/team-config.yaml\"<\/span>\n\n<span class=\"nb\">echo<\/span> <span class=\"s2\">\"\ud83d\udd0d Validating goose configuration...\"<\/span>\n\n<span class=\"c\"># Compare with team config<\/span>\n<span class=\"k\">if <\/span>diff <span class=\"nt\">-q<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$CONFIG_FILE<\/span><span class=\"s2\">\"<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$TEAM_CONFIG<\/span><span class=\"s2\">\"<\/span> <span class=\"o\">&gt;<\/span> \/dev\/null<span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u2705 Configuration is up to date\"<\/span>\n<span class=\"k\">else\n    <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u26a0\ufe0f  Configuration differs from team config\"<\/span>\n    <span class=\"nb\">echo<\/span> <span class=\"s2\">\"\"<\/span>\n    <span class=\"nb\">echo<\/span> <span class=\"s2\">\"Differences:\"<\/span>\n    diff <span class=\"s2\">\"<\/span><span class=\"nv\">$CONFIG_FILE<\/span><span class=\"s2\">\"<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$TEAM_CONFIG<\/span><span class=\"s2\">\"<\/span>\n    <span class=\"nb\">echo<\/span> <span class=\"s2\">\"\"<\/span>\n    <span class=\"nb\">read<\/span> <span class=\"nt\">-p<\/span> <span class=\"s2\">\"Update to team config? (y\/n) \"<\/span> <span class=\"nt\">-n<\/span> 1 <span class=\"nt\">-r<\/span>\n    <span class=\"nb\">echo\n    <\/span><span class=\"k\">if<\/span> <span class=\"o\">[[<\/span> <span class=\"nv\">$REPLY<\/span> <span class=\"o\">=<\/span>~ ^[Yy]<span class=\"nv\">$ <\/span><span class=\"o\">]]<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n        <\/span><span class=\"nb\">cp<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$TEAM_CONFIG<\/span><span class=\"s2\">\"<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$CONFIG_FILE<\/span><span class=\"s2\">\"<\/span>\n        <span class=\"nb\">echo<\/span> <span class=\"s2\">\"\u2705 Configuration updated\"<\/span>\n    <span class=\"k\">fi\nfi<\/span>\n\n<span class=\"c\"># 2. Add to pre-commit hook<\/span>\n<span class=\"c\"># .git\/hooks\/pre-commit<\/span>\n<span class=\"c\">#!\/bin\/bash<\/span>\n.\/scripts\/validate-config.sh\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Prevention<\/strong><\/p>\n\n<ul>\n<li>Regular configuration audits<\/li>\n<li>Automated sync scripts<\/li>\n<li>Clear process for config changes<\/li>\n<li>Version config files in git<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Issue 4: Slow Performance\n<\/h4>\n\n<p><strong>Problem<\/strong>: goose takes a long time to respond<\/p>\n\n<p><strong>Why This Happens<\/strong><\/p>\n\n<ul>\n<li>Extensions with long timeouts<\/li>\n<li>Expensive operations in tool implementations<\/li>\n<li>Network latency to remote services<\/li>\n<li>Large context windows<\/li>\n<li>Inefficient prompts<\/li>\n<\/ul>\n\n<p><strong>Solutions<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"c1\"># 1. Optimize extension timeouts<\/span>\n<span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">slow_extension<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>  <span class=\"c1\"># Reduce if possible<\/span>\n\n<span class=\"c1\"># 2. Use caching where appropriate<\/span>\n<span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">api_extension<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">ENABLE_CACHE<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">true\"<\/span>\n      <span class=\"na\">CACHE_TTL<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">3600\"<\/span>  <span class=\"c1\"># 1 hour<\/span>\n\n<span class=\"c1\"># 3. Configure reasonable context limits<\/span>\n<span class=\"na\">preferences<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">max_tokens<\/span><span class=\"pi\">:<\/span> <span class=\"m\">4000<\/span>  <span class=\"c1\"># Don't go overboard<\/span>\n  <span class=\"na\">max_context_files<\/span><span class=\"pi\">:<\/span> <span class=\"m\">10<\/span>  <span class=\"c1\"># Limit files in context<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Prevention<\/strong><\/p>\n\n<ul>\n<li>Profile extensions before deploying<\/li>\n<li>Set reasonable timeout defaults<\/li>\n<li>Monitor response times<\/li>\n<li>Optimize custom extensions<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Issue 5: Permission Errors\n<\/h4>\n\n<p><strong>Problem<\/strong>: goose can't access files or resources<\/p>\n\n<p><strong>Why This Happens<\/strong><\/p>\n\n<ul>\n<li>Insufficient file permissions<\/li>\n<li>Extensions trying to access restricted paths<\/li>\n<li>Environment variables pointing to restricted locations<\/li>\n<li>Security policies blocking access<\/li>\n<\/ul>\n\n<p><strong>Solutions<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># 1. Check file permissions<\/span>\n<span class=\"nb\">ls<\/span> <span class=\"nt\">-la<\/span> ~\/.config\/goose\/\n<span class=\"c\"># Ensure user has read\/write access<\/span>\n\n<span class=\"c\"># 2. Fix permissions<\/span>\n<span class=\"nb\">chmod <\/span>755 ~\/.config\/goose\n<span class=\"nb\">chmod <\/span>644 ~\/.config\/goose\/config.yaml\n\n<span class=\"c\"># 3. Check extension permissions<\/span>\n<span class=\"c\"># Extensions should not require root\/admin<\/span>\n\n<span class=\"c\"># 4. Verify environment variables<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"nv\">$HOME<\/span>  <span class=\"c\"># Should be your home directory<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"nv\">$GOOSE_CONFIG_DIR<\/span>  <span class=\"c\"># Should be writable<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Prevention<\/strong><\/p>\n\n<ul>\n<li>Document required permissions<\/li>\n<li>Test on fresh user accounts<\/li>\n<li>Avoid requiring elevated permissions<\/li>\n<li>Use user-specific paths<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Governance and Policies\n<\/h3>\n\n<p>Establish clear policies for team goose usage.<\/p>\n\n<h4>\n  \n  \n  Usage Policy Template\n<\/h4>\n\n<p><code>docs\/goose-usage-policy.md<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code><span class=\"gh\"># goose Usage Policy<\/span>\n\n<span class=\"gu\">## Acceptable Use<\/span>\n\ngoose is provided to improve developer productivity. Acceptable uses include:\n\n\u2705 <span class=\"gs\">**Allowed:**<\/span>\n<span class=\"p\">-<\/span> Code review and analysis\n<span class=\"p\">-<\/span> Documentation generation\n<span class=\"p\">-<\/span> Test writing\n<span class=\"p\">-<\/span> Debugging assistance\n<span class=\"p\">-<\/span> Learning new technologies\n<span class=\"p\">-<\/span> Refactoring guidance\n<span class=\"p\">-<\/span> Architecture discussions\n\n\u274c <span class=\"gs\">**Not Allowed:**<\/span>\n<span class=\"p\">-<\/span> Processing confidential customer data\n<span class=\"p\">-<\/span> Generating production secrets or keys\n<span class=\"p\">-<\/span> Making production deployments without review\n<span class=\"p\">-<\/span> Sharing API keys or credentials\n<span class=\"p\">-<\/span> Using goose to bypass code review processes\n<span class=\"p\">-<\/span> Bulk automated operations without approval\n\n<span class=\"gu\">## Data Privacy<\/span>\n<span class=\"p\">\n-<\/span> <span class=\"gs\">**Code**<\/span>: goose processes code snippets to provide assistance\n<span class=\"p\">-<\/span> <span class=\"gs\">**Sharing**<\/span>: Code context is sent to LLM providers (OpenAI, Anthropic, etc.)\n<span class=\"p\">-<\/span> <span class=\"gs\">**Retention**<\/span>: Check your LLM provider's data retention policy\n<span class=\"p\">-<\/span> <span class=\"gs\">**Sensitive Data**<\/span>: Do not include PII, secrets, or confidential data in prompts\n\n<span class=\"gu\">## Security Guidelines<\/span>\n<span class=\"p\">\n-<\/span> <span class=\"gs\">**API Keys**<\/span>: Keep personal, never share\n<span class=\"p\">-<\/span> <span class=\"gs\">**Extensions**<\/span>: Only install approved extensions\n<span class=\"p\">-<\/span> <span class=\"gs\">**Updates**<\/span>: Keep goose and extensions updated\n<span class=\"p\">-<\/span> <span class=\"gs\">**Incidents**<\/span>: Report security concerns to #security-team\n\n<span class=\"gu\">## Cost Management<\/span>\n<span class=\"p\">\n-<\/span> <span class=\"gs\">**Model Selection**<\/span>: Use gpt-4o-mini by default\n<span class=\"p\">-<\/span> <span class=\"gs\">**Usage Limits**<\/span>: Stay within monthly budget (check dashboard)\n<span class=\"p\">-<\/span> <span class=\"gs\">**Monitoring**<\/span>: Review your usage weekly\n<span class=\"p\">-<\/span> <span class=\"gs\">**Alerts**<\/span>: Set up billing alerts in OpenAI dashboard\n\n<span class=\"gu\">## Quality Standards<\/span>\n<span class=\"p\">\n-<\/span> <span class=\"gs\">**Always Review**<\/span>: Never blindly accept AI-generated code\n<span class=\"p\">-<\/span> <span class=\"gs\">**Test**<\/span>: All code must pass tests before committing\n<span class=\"p\">-<\/span> <span class=\"gs\">**Document**<\/span>: Add comments explaining AI-assisted code\n<span class=\"p\">-<\/span> <span class=\"gs\">**Responsibility**<\/span>: You own all code you commit\n\n<span class=\"gu\">## Reporting Issues<\/span>\n<span class=\"p\">\n-<\/span> <span class=\"gs\">**Bugs**<\/span>: #goose-support\n<span class=\"p\">-<\/span> <span class=\"gs\">**Policy Violations**<\/span>: #engineering-leads\n<span class=\"p\">-<\/span> <span class=\"gs\">**Security Concerns**<\/span>: #security-team\n<span class=\"p\">\n---\n<\/span>\n<span class=\"gs\">**Acknowledgment**<\/span>: By using goose, you agree to follow this policy.\n\nLast Updated: 2025-10-25\nPolicy Owner: Engineering Leadership\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Access Control\n<\/h4>\n\n<p>For enterprises, implement role-based access:<br>\n<code>scripts\/check-access.py<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\">#!\/usr\/bin\/env python3\n<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\nCheck if user has access to requested goose configuration\n<\/span><span class=\"sh\">\"\"\"<\/span>\n\n<span class=\"kn\">import<\/span> <span class=\"n\">sys<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">requests<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">os<\/span>\n\n<span class=\"c1\"># Integration with your identity provider\n<\/span><span class=\"k\">def<\/span> <span class=\"nf\">check_user_access<\/span><span class=\"p\">(<\/span><span class=\"n\">email<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">role<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Check if user has access to role configuration<\/span><span class=\"sh\">\"\"\"<\/span>\n\n    <span class=\"c1\"># Example: Check against internal API\n<\/span>    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span>\n        <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/api.company.com\/access\/goose<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Authorization<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Bearer <\/span><span class=\"si\">{<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">COMPANY_API_KEY<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">},<\/span>\n        <span class=\"n\">params<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">email<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">email<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">role<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">role<\/span><span class=\"p\">}<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">json<\/span><span class=\"p\">().<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">has_access<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"bp\">False<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">main<\/span><span class=\"p\">():<\/span>\n    <span class=\"n\">email<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">USER_EMAIL<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">requested_role<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sys<\/span><span class=\"p\">.<\/span><span class=\"n\">argv<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"k\">if<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">sys<\/span><span class=\"p\">.<\/span><span class=\"n\">argv<\/span><span class=\"p\">)<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">1<\/span> <span class=\"k\">else<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">developer<\/span><span class=\"sh\">\"<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"nf\">check_user_access<\/span><span class=\"p\">(<\/span><span class=\"n\">email<\/span><span class=\"p\">,<\/span> <span class=\"n\">requested_role<\/span><span class=\"p\">):<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\u2705 Access granted: <\/span><span class=\"si\">{<\/span><span class=\"n\">requested_role<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">sys<\/span><span class=\"p\">.<\/span><span class=\"nf\">exit<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\u274c Access denied: <\/span><span class=\"si\">{<\/span><span class=\"n\">requested_role<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Contact #platform-team to request access<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">sys<\/span><span class=\"p\">.<\/span><span class=\"nf\">exit<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"n\">__name__<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">__main__<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span>\n    <span class=\"nf\">main<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Integrate into setup script<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># In setup-goose.sh<\/span>\npython scripts\/check-access.py <span class=\"nv\">$ROLE<\/span> <span class=\"o\">||<\/span> <span class=\"nb\">exit <\/span>1\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Monitoring and Cost Management\n<\/h3>\n\n<p>Track usage and costs across your team.<\/p>\n\n<h4>\n  \n  \n  Cost Tracking Dashboard\n<\/h4>\n\n<p>Create a simple dashboard to monitor API usage:<br>\n<code>scripts\/cost-tracker.py<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\">#!\/usr\/bin\/env python3\n<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\nTrack goose API costs across team\n<\/span><span class=\"sh\">\"\"\"<\/span>\n\n<span class=\"kn\">import<\/span> <span class=\"n\">requests<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">os<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">datetime<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">datetime<\/span><span class=\"p\">,<\/span> <span class=\"n\">timedelta<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">collections<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">defaultdict<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">get_openai_usage<\/span><span class=\"p\">(<\/span><span class=\"n\">api_key<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">days<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">30<\/span><span class=\"p\">):<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Get OpenAI usage for last N days<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">end_date<\/span> <span class=\"o\">=<\/span> <span class=\"n\">datetime<\/span><span class=\"p\">.<\/span><span class=\"nf\">now<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">start_date<\/span> <span class=\"o\">=<\/span> <span class=\"n\">end_date<\/span> <span class=\"o\">-<\/span> <span class=\"nf\">timedelta<\/span><span class=\"p\">(<\/span><span class=\"n\">days<\/span><span class=\"o\">=<\/span><span class=\"n\">days<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">requests<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/api.openai.com\/v1\/usage<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Authorization<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Bearer <\/span><span class=\"si\">{<\/span><span class=\"n\">api_key<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">},<\/span>\n        <span class=\"n\">params<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">start_date<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">start_date<\/span><span class=\"p\">.<\/span><span class=\"nf\">strftime<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">%Y-%m-%d<\/span><span class=\"sh\">\"<\/span><span class=\"p\">),<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">end_date<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">end_date<\/span><span class=\"p\">.<\/span><span class=\"nf\">strftime<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">%Y-%m-%d<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"n\">response<\/span><span class=\"p\">.<\/span><span class=\"nf\">json<\/span><span class=\"p\">()<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">calculate_costs<\/span><span class=\"p\">(<\/span><span class=\"n\">usage_data<\/span><span class=\"p\">:<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Calculate costs by model<\/span><span class=\"sh\">\"\"\"<\/span>\n\n    <span class=\"c1\"># Pricing (as of 2025)\n<\/span>    <span class=\"n\">pricing<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">gpt-4o<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">input<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"mf\">0.0025<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">output<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"mf\">0.01<\/span><span class=\"p\">},<\/span>  <span class=\"c1\"># per 1K tokens\n<\/span>        <span class=\"sh\">\"<\/span><span class=\"s\">gpt-4o-mini<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">input<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"mf\">0.00015<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">output<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"mf\">0.0006<\/span><span class=\"p\">},<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">gpt-4<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">input<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"mf\">0.03<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">output<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"mf\">0.06<\/span><span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"n\">costs<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">defaultdict<\/span><span class=\"p\">(<\/span><span class=\"nb\">float<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">for<\/span> <span class=\"n\">entry<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">usage_data<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">data<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"p\">[]):<\/span>\n        <span class=\"n\">model<\/span> <span class=\"o\">=<\/span> <span class=\"n\">entry<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">model<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">input_tokens<\/span> <span class=\"o\">=<\/span> <span class=\"n\">entry<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">input_tokens<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">output_tokens<\/span> <span class=\"o\">=<\/span> <span class=\"n\">entry<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">output_tokens<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"n\">model<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">pricing<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">costs<\/span><span class=\"p\">[<\/span><span class=\"n\">model<\/span><span class=\"p\">]<\/span> <span class=\"o\">+=<\/span> <span class=\"p\">(<\/span>\n                <span class=\"p\">(<\/span><span class=\"n\">input_tokens<\/span> <span class=\"o\">\/<\/span> <span class=\"mi\">1000<\/span><span class=\"p\">)<\/span> <span class=\"o\">*<\/span> <span class=\"n\">pricing<\/span><span class=\"p\">[<\/span><span class=\"n\">model<\/span><span class=\"p\">][<\/span><span class=\"sh\">\"<\/span><span class=\"s\">input<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span> <span class=\"o\">+<\/span>\n                <span class=\"p\">(<\/span><span class=\"n\">output_tokens<\/span> <span class=\"o\">\/<\/span> <span class=\"mi\">1000<\/span><span class=\"p\">)<\/span> <span class=\"o\">*<\/span> <span class=\"n\">pricing<\/span><span class=\"p\">[<\/span><span class=\"n\">model<\/span><span class=\"p\">][<\/span><span class=\"sh\">\"<\/span><span class=\"s\">output<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span>\n            <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"nf\">dict<\/span><span class=\"p\">(<\/span><span class=\"n\">costs<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">main<\/span><span class=\"p\">():<\/span>\n    <span class=\"c1\"># This should be a company-wide API key for monitoring\n<\/span>    <span class=\"n\">api_key<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">OPENAI_MONITOR_KEY<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">usage<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_openai_usage<\/span><span class=\"p\">(<\/span><span class=\"n\">api_key<\/span><span class=\"p\">,<\/span> <span class=\"n\">days<\/span><span class=\"o\">=<\/span><span class=\"mi\">30<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">costs<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">calculate_costs<\/span><span class=\"p\">(<\/span><span class=\"n\">usage<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">total_cost<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">sum<\/span><span class=\"p\">(<\/span><span class=\"n\">costs<\/span><span class=\"p\">.<\/span><span class=\"nf\">values<\/span><span class=\"p\">())<\/span>\n\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\ud83d\udcca goose Cost Report (Last 30 Days)<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">=<\/span><span class=\"sh\">\"<\/span> <span class=\"o\">*<\/span> <span class=\"mi\">50<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Total: $<\/span><span class=\"si\">{<\/span><span class=\"n\">total_cost<\/span><span class=\"si\">:<\/span><span class=\"p\">.<\/span><span class=\"mi\">2<\/span><span class=\"n\">f<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">()<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">By Model:<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">model<\/span><span class=\"p\">,<\/span> <span class=\"n\">cost<\/span> <span class=\"ow\">in<\/span> <span class=\"nf\">sorted<\/span><span class=\"p\">(<\/span><span class=\"n\">costs<\/span><span class=\"p\">.<\/span><span class=\"nf\">items<\/span><span class=\"p\">(),<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">x<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">],<\/span> <span class=\"n\">reverse<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">):<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">  <\/span><span class=\"si\">{<\/span><span class=\"n\">model<\/span><span class=\"si\">:<\/span><span class=\"mi\">20<\/span><span class=\"si\">}<\/span><span class=\"s\"> $<\/span><span class=\"si\">{<\/span><span class=\"n\">cost<\/span><span class=\"si\">:<\/span><span class=\"o\">&gt;<\/span><span class=\"mf\">10.2<\/span><span class=\"n\">f<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"c1\"># Alert if over budget\n<\/span>    <span class=\"n\">budget<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">float<\/span><span class=\"p\">(<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">MONTHLY_BUDGET<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">1000<\/span><span class=\"sh\">\"<\/span><span class=\"p\">))<\/span>\n    <span class=\"k\">if<\/span> <span class=\"n\">total_cost<\/span> <span class=\"o\">&gt;<\/span> <span class=\"n\">budget<\/span><span class=\"p\">:<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\u26a0\ufe0f  WARNING: Over budget by $<\/span><span class=\"si\">{<\/span><span class=\"n\">total_cost<\/span> <span class=\"o\">-<\/span> <span class=\"n\">budget<\/span><span class=\"si\">:<\/span><span class=\"p\">.<\/span><span class=\"mi\">2<\/span><span class=\"n\">f<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Consider:<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">- Using gpt-4o-mini more often<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">- Reviewing high-usage team members<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">- Optimizing prompts to reduce tokens<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"n\">__name__<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">__main__<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span>\n    <span class=\"nf\">main<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Run weekly<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Add to cron or CI\/CD<\/span>\n0 9 <span class=\"k\">*<\/span> <span class=\"k\">*<\/span> 1 python scripts\/cost-tracker.py | mail <span class=\"nt\">-s<\/span> <span class=\"s2\">\"goose Weekly Cost Report\"<\/span> team@company.com\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Usage Analytics\n<\/h4>\n\n<p>Track which extensions and workflows are most popular:<br>\n<code>scripts\/usage-analytics.py<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\">#!\/usr\/bin\/env python3\n<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\nAnalyze goose usage patterns across team\n<\/span><span class=\"sh\">\"\"\"<\/span>\n\n<span class=\"kn\">import<\/span> <span class=\"n\">yaml<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">pathlib<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Path<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">collections<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Counter<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">matplotlib.pyplot<\/span> <span class=\"k\">as<\/span> <span class=\"n\">plt<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">analyze_configurations<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Analyze what extensions teams are using<\/span><span class=\"sh\">\"\"\"<\/span>\n\n    <span class=\"c1\"># Scan team configurations\n<\/span>    <span class=\"n\">config_dir<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Path<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">.goose<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">extensions_used<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Counter<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"k\">for<\/span> <span class=\"n\">config_file<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">config_dir<\/span><span class=\"p\">.<\/span><span class=\"nf\">glob<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">*-config.yaml<\/span><span class=\"sh\">\"<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">with<\/span> <span class=\"nf\">open<\/span><span class=\"p\">(<\/span><span class=\"n\">config_file<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">f<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">config<\/span> <span class=\"o\">=<\/span> <span class=\"n\">yaml<\/span><span class=\"p\">.<\/span><span class=\"nf\">safe_load<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">for<\/span> <span class=\"n\">ext_name<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">config<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">extensions<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"p\">{}).<\/span><span class=\"nf\">keys<\/span><span class=\"p\">():<\/span>\n            <span class=\"n\">extensions_used<\/span><span class=\"p\">[<\/span><span class=\"n\">ext_name<\/span><span class=\"p\">]<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">1<\/span>\n\n    <span class=\"c1\"># Generate report\n<\/span>    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\ud83d\udcca Extension Usage Report<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">=<\/span><span class=\"sh\">\"<\/span> <span class=\"o\">*<\/span> <span class=\"mi\">50<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Most Popular Extensions:<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">ext<\/span><span class=\"p\">,<\/span> <span class=\"n\">count<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">extensions_used<\/span><span class=\"p\">.<\/span><span class=\"nf\">most_common<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">):<\/span>\n        <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">  <\/span><span class=\"si\">{<\/span><span class=\"n\">ext<\/span><span class=\"si\">:<\/span><span class=\"mi\">30<\/span><span class=\"si\">}<\/span><span class=\"s\"> <\/span><span class=\"si\">{<\/span><span class=\"n\">count<\/span><span class=\"si\">:<\/span><span class=\"mi\">3<\/span><span class=\"si\">}<\/span><span class=\"s\"> configs<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\"># Create visualization\n<\/span>    <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"nf\">figure<\/span><span class=\"p\">(<\/span><span class=\"n\">figsize<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">6<\/span><span class=\"p\">))<\/span>\n    <span class=\"n\">exts<\/span><span class=\"p\">,<\/span> <span class=\"n\">counts<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">zip<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">extensions_used<\/span><span class=\"p\">.<\/span><span class=\"nf\">most_common<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">))<\/span>\n    <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"nf\">barh<\/span><span class=\"p\">(<\/span><span class=\"n\">exts<\/span><span class=\"p\">,<\/span> <span class=\"n\">counts<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"nf\">xlabel<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Number of Configurations<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"nf\">title<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Top 10 goose Extensions by Usage<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"nf\">tight_layout<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"nf\">savefig<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">goose-usage-report.png<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"se\">\\n<\/span><span class=\"s\">\ud83d\udcc8 Chart saved: goose-usage-report.png<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"n\">__name__<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">__main__<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span>\n    <span class=\"nf\">analyze_configurations<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Budget Alerts\n<\/h4>\n\n<p>Set up automated alerts when approaching budget limits:<br>\n<code>scripts\/budget-alert.sh<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\">#!\/bin\/bash<\/span>\n<span class=\"c\"># Check if approaching monthly budget<\/span>\n\n<span class=\"nv\">CURRENT_SPEND<\/span><span class=\"o\">=<\/span><span class=\"si\">$(<\/span>python scripts\/cost-tracker.py <span class=\"nt\">--json<\/span> | jq <span class=\"s1\">'.total_cost'<\/span><span class=\"si\">)<\/span>\n<span class=\"nv\">BUDGET<\/span><span class=\"o\">=<\/span><span class=\"k\">${<\/span><span class=\"nv\">MONTHLY_BUDGET<\/span><span class=\"k\">:-<\/span><span class=\"nv\">1000<\/span><span class=\"k\">}<\/span>\n<span class=\"nv\">THRESHOLD<\/span><span class=\"o\">=<\/span>0.8  <span class=\"c\"># Alert at 80%<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"o\">((<\/span> <span class=\"si\">$(<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"<\/span><span class=\"nv\">$CURRENT_SPEND<\/span><span class=\"s2\"> &gt; (<\/span><span class=\"nv\">$BUDGET<\/span><span class=\"s2\"> * <\/span><span class=\"nv\">$THRESHOLD<\/span><span class=\"s2\">)\"<\/span> | bc <span class=\"nt\">-l<\/span><span class=\"si\">)<\/span> <span class=\"o\">))<\/span><span class=\"p\">;<\/span> <span class=\"k\">then\n    <\/span><span class=\"nv\">PERCENT<\/span><span class=\"o\">=<\/span><span class=\"si\">$(<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">\"scale=1; (<\/span><span class=\"nv\">$CURRENT_SPEND<\/span><span class=\"s2\"> \/ <\/span><span class=\"nv\">$BUDGET<\/span><span class=\"s2\">) * 100\"<\/span> | bc<span class=\"si\">)<\/span>\n\n    <span class=\"c\"># Send Slack alert<\/span>\n    curl <span class=\"nt\">-X<\/span> POST <span class=\"nv\">$SLACK_WEBHOOK_URL<\/span> <span class=\"se\">\\<\/span>\n      <span class=\"nt\">-H<\/span> <span class=\"s1\">'Content-Type: application\/json'<\/span> <span class=\"se\">\\<\/span>\n      <span class=\"nt\">-d<\/span> <span class=\"s2\">\"{\n        <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">text<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">: <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">\u26a0\ufe0f goose Budget Alert<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">,\n        <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">blocks<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">: [\n          {\n            <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">type<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">: <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">section<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">,\n            <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">text<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">: {\n              <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">type<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">: <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">mrkdwn<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">,\n              <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">text<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">: <\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">*goose Monthly Budget Alert*<\/span><span class=\"se\">\\n\\n<\/span><span class=\"s2\">Current: <\/span><span class=\"se\">\\$<\/span><span class=\"s2\">CURRENT_SPEND<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">Budget: <\/span><span class=\"se\">\\$<\/span><span class=\"s2\">BUDGET<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">Usage: <\/span><span class=\"nv\">$PERCENT<\/span><span class=\"s2\">%<\/span><span class=\"se\">\\n\\n<\/span><span class=\"s2\">Review usage at: [Dashboard Link]<\/span><span class=\"se\">\\\"<\/span><span class=\"s2\">\n            }\n          }\n        ]\n      }\"<\/span>\n<span class=\"k\">fi<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Case Studies\n<\/h3>\n\n<p>Learn from teams who've successfully deployed goose.<\/p>\n\n<h4>\n  \n  \n  Case Study 1: Startup (15 developers)\n<\/h4>\n\n<p><strong>Challenge<\/strong>: Fast-moving startup needed consistent tooling across growing team<\/p>\n\n<p><strong>Solution<\/strong><\/p>\n\n<ul>\n<li>Implemented Strategy 1 (Shared Base Configuration)<\/li>\n<li>Single setup script in repo<\/li>\n<li>Weekly sync meetings to discuss new workflows<\/li>\n<li>Slack channel for quick questions<\/li>\n<\/ul>\n\n<p><strong>Results<\/strong><\/p>\n\n<ul>\n<li>100% team adoption in 2 weeks<\/li>\n<li>Reduced onboarding time from 3 days to 4 hours<\/li>\n<li>Standardized code review process<\/li>\n<li>30% faster PR turnaround<\/li>\n<\/ul>\n\n<p><strong>Key Learnings<\/strong><\/p>\n\n<ul>\n<li>Keep it simple at first<\/li>\n<li>Document everything in README<\/li>\n<li>Have \"office hours\" for questions<\/li>\n<li>Start with one workflow everyone uses<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Case Study 2: Mid-size Company (50 developers)\n<\/h4>\n\n<p><strong>Challenge:<\/strong> Multiple teams with different tech stacks and needs<\/p>\n\n<p><strong>Solution<\/strong><\/p>\n\n<ul>\n<li>Implemented Strategy 2 (Per-Environment Configurations)<\/li>\n<li>Separate configs for Backend, Frontend, DevOps, QA<\/li>\n<li>Central platform team maintains extensions<\/li>\n<li>Monthly training sessions<\/li>\n<\/ul>\n\n<p><strong>Results<\/strong><\/p>\n\n<ul>\n<li>85% team adoption in 3 months<\/li>\n<li>4 custom internal extensions built<\/li>\n<li>Reduced repetitive tasks by 40%<\/li>\n<li>Improved documentation quality<\/li>\n<\/ul>\n\n<p><strong>Key Learnings<\/strong><\/p>\n\n<ul>\n<li>Role-specific configs crucial<\/li>\n<li>Need dedicated \"goose champion\" per team<\/li>\n<li>Custom extensions provide huge value<\/li>\n<li>Regular training keeps engagement high<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Case Study 3: Enterprise (200+ developers)\n<\/h4>\n\n<p><strong>Challenge<\/strong>: Large organization with strict compliance and security requirements<\/p>\n\n<p><strong>Solution<\/strong><\/p>\n\n<ul>\n<li>Implemented Strategy 3 (Team Templates)<\/li>\n<li>Configuration generator with access control<\/li>\n<li>Integration with identity management<\/li>\n<li>Centralized cost tracking and alerts<\/li>\n<li>Quarterly governance reviews<\/li>\n<\/ul>\n\n<p><strong>Results<\/strong><\/p>\n\n<ul>\n<li>70% adoption across engineering org<\/li>\n<li>Passed security audit<\/li>\n<li>$50K\/month in productivity gains<\/li>\n<li>Reduced API costs by 30% with smart model selection<\/li>\n<\/ul>\n\n<p><strong>Key Learnings<\/strong><\/p>\n\n<ul>\n<li>Security and compliance can't be afterthoughts<\/li>\n<li>Need executive sponsorship<\/li>\n<li>Cost monitoring essential at scale<\/li>\n<li>Change management takes time<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Conclusion\n<\/h2>\n\n<p>Deploying goose across a team requires more than just installing the software. Success comes from:<\/p>\n\n<ol>\n<li>\n<strong>Clear Configuration Management<\/strong>: Choose a strategy that fits your team size and needs<\/li>\n<li>\n<strong>Security-First Approach<\/strong>: Never compromise on API key management<\/li>\n<li>\n<strong>Documentation<\/strong>: Write everything down\u2014your future team members will thank you<\/li>\n<li>\n<strong>Workflows<\/strong>: Establish patterns everyone can follow<\/li>\n<li>\n<strong>Governance<\/strong>: Set policies and monitor compliance<\/li>\n<li>\n<strong>Continuous Improvement<\/strong>: Gather feedback and iterate<\/li>\n<\/ol>\n\n<h3>\n  \n  \n  Quick Start Recommendations by Team Size\n<\/h3>\n\n<p><strong>Small Teams (&lt; 15):<\/strong><\/p>\n\n<ul>\n<li>Use Strategy 1 (Shared Base Configuration)<\/li>\n<li>Keep configs simple<\/li>\n<li>Focus on 2-3 core workflows<\/li>\n<li>Use environment variables for secrets<\/li>\n<\/ul>\n\n<p><strong>Medium Teams (15-50):<\/strong><\/p>\n\n<ul>\n<li>Use Strategy 2 (Per-Environment Configurations)<\/li>\n<li>Create role-specific setups<\/li>\n<li>Build 1-2 custom extensions<\/li>\n<li>Establish governance policies<\/li>\n<\/ul>\n\n<p><strong>Large Teams (50+):<\/strong><\/p>\n\n<ul>\n<li>Use Strategy 3 (Team Templates)<\/li>\n<li>Implement access control<\/li>\n<li>Build comprehensive monitoring<\/li>\n<li>Create dedicated platform team<\/li>\n<\/ul>\n\n<p><strong>Next Steps<\/strong><\/p>\n\n<ol>\n<li>\n<strong>Assess Your Team<\/strong>: Size, structure, needs<\/li>\n<li>\n<strong>Choose a Strategy<\/strong>: Based on recommendations above<\/li>\n<li>\n<strong>Start Small<\/strong>: One team or project first<\/li>\n<li>\n<strong>Document<\/strong>: Create setup guides and workflows<\/li>\n<li>\n<strong>Train<\/strong>: Run workshops and create resources<\/li>\n<li>\n<strong>Monitor<\/strong>: Track usage and costs<\/li>\n<li>\n<strong>Iterate<\/strong>: Gather feedback and improve<\/li>\n<li>\n<strong>Scale<\/strong>: Roll out to wider organization<\/li>\n<\/ol>\n\n<h3>\n  \n  \n  Resources\n<\/h3>\n\n<ul>\n<li><a href=\"https:\/\/block.github.io\/goose\" rel=\"noopener noreferrer\">goose Documentation<\/a><\/li>\n<li><a href=\"https:\/\/modelcontextprotocol.io\/\" rel=\"noopener noreferrer\">MCP Extensions<\/a><\/li>\n<li><a href=\"https:\/\/discord.gg\/block-opensource\" rel=\"noopener noreferrer\">Community<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/block\/goose\" rel=\"noopener noreferrer\">Example Configs<\/a><\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Getting Help\n<\/h4>\n\n<p><strong>Questions about team deployment?<\/strong><\/p>\n\n<ul>\n<li>Join #goose-users on Discord<\/li>\n<li>Post in GitHub Discussions<\/li>\n<li>Reach out to platform team at your company<\/li>\n<li>Share your learnings with the community<\/li>\n<\/ul>\n\n\n\n\n<p><em>This guide is part of the goose documentation series. See also:<\/em><\/p>\n\n<ul>\n<li><a href=\"https:\/\/dev.to\/lymah\/getting-started-with-goose-on-windows-30bh\">Getting Started with goose on Windows<\/a><\/li>\n<li><a href=\"https:\/\/dev.to\/lymah\/best-practices-for-prompt-engineering-with-goose-3m6h\">Best Practices for Prompt Engineering with goose<\/a><\/li>\n<li><a href=\"https:\/\/dev.to\/lymah\/deep-dive-into-gooses-extension-system-and-model-context-protocol-mcp-3ehl\">Deep Dive into goose's Extension System and MCP<\/a><\/li>\n<\/ul>\n\n<p><strong><em>Happy team coding with goose! \ud83e\udda2<\/em><\/strong><\/p>\n\n","category":["goose","ai","llm","opensource"]},{"title":"Deep Dive into goose's Extension System and Model Context Protocol (MCP)","pubDate":"Tue, 21 Oct 2025 15:43:22 +0000","link":"https:\/\/dev.to\/lymah\/deep-dive-into-gooses-extension-system-and-model-context-protocol-mcp-3ehl","guid":"https:\/\/dev.to\/lymah\/deep-dive-into-gooses-extension-system-and-model-context-protocol-mcp-3ehl","description":"<h2>\n  \n  \n  Table of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>\nUnderstanding the Model Context Protocol (MCP)\n\n<ul>\n<li>What is MCP?<\/li>\n<li>Why MCP Matters for goose<\/li>\n<li>MCP Architecture Overview<\/li>\n<li>Host (goose Application)<\/li>\n<li>Clients<\/li>\n<li>Servers (Extensions)<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nMCP Core Concepts\n\n<ul>\n<li>1. Primitives: The Building Blocks<\/li>\n<li>Prompts<\/li>\n<li>Resources<\/li>\n<li>Tools<\/li>\n<li>2. Message Types<\/li>\n<li>3. Capability Negotiation<\/li>\n<li>Why Capability Negotiation Matters<\/li>\n<li>4. Connection Lifecycle<\/li>\n<li>5. Transport Mechanisms<\/li>\n<li>STDIO (Standard Input\/Output)<\/li>\n<li>SSE (Server-Sent Events over HTTP)<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\ngoose's Extension Architecture\n\n<ul>\n<li>How goose Implements MCP<\/li>\n<li>Extension Categories in goose<\/li>\n<li>Extension Configuration<\/li>\n<li>Managing Extensions<\/li>\n<li>Via Desktop UI<\/li>\n<li>Deep Link Protocol<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nBuilding Custom MCP Extensions\n\n<ul>\n<li>Development Workflow<\/li>\n<li>Example: PostgreSQL MCP Server<\/li>\n<li>Step 1: Project Setup<\/li>\n<li>Step 2: Implement Server Logic<\/li>\n<li>Step 3: Configure Project<\/li>\n<li>Step 4: Test with MCP Inspector<\/li>\n<li>Step 5: Integrate with goose<\/li>\n<li>Step 6: Use the Extension<\/li>\n<li>Advanced Extension Patterns<\/li>\n<li>1. Stateful Extensions<\/li>\n<li>2. Streaming Responses<\/li>\n<li>3. Resource Subscriptions<\/li>\n<li>4. Error Handling Best Practices<\/li>\n<li>5. Authentication and Security<\/li>\n<li>6. Rate Limiting<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nProduction Best Practices\n\n<ul>\n<li>1. Logging and Observability<\/li>\n<li>2. Configuration Management<\/li>\n<li>3. Testing Extensions<\/li>\n<li>4. Performance Optimization<\/li>\n<li>5. Security Hardening<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nPublishing and Distribution\n\n<ul>\n<li>1. Publishing to PyPI<\/li>\n<li>2. Creating Installation Links<\/li>\n<li>3. Documentation<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nAdvanced Topics\n\n<ul>\n<li>1. Multi-Protocol Support<\/li>\n<li>2. Dynamic Tool Generation<\/li>\n<li>3. Composite Extensions<\/li>\n<li>4. Webhook Integration<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nTroubleshooting\n\n<ul>\n<li>Common Issues and Solutions<\/li>\n<li>1. Connection Timeout<\/li>\n<li>2. Environment Variables Not Loading<\/li>\n<li>3. Tool Not Appearing in Goose<\/li>\n<li>4. Permission Denied Errors<\/li>\n<li>5. Import Errors<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nPerformance Optimization\n\n<ul>\n<li>Benchmarking Extensions<\/li>\n<li>Profiling<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nReal-World Extension Examples\n\n<ul>\n<li>1. GitHub Integration<\/li>\n<li>2. Slack Integration<\/li>\n<li>3. Jira Integration<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nConclusion\n\n<ul>\n<li>Key Takeaways<\/li>\n<li>Moving Forward<\/li>\n<li>Additional Resources<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Introduction\n<\/h2>\n\n<p><a href=\"https:\/\/block.github.io\/goose\/docs\/category\/mcp-servers\" rel=\"noopener noreferrer\">goose's<\/a> true power lies not just in its AI capabilities, but in its extensibility through the Model Context Protocol <a href=\"https:\/\/modelcontextprotocol.io\/\" rel=\"noopener noreferrer\">(MCP)<\/a>. <strong><em>MCP is an open standard that enables developers to build secure, two-way connections between AI systems and external data sources<\/em><\/strong>, transforming goose from a capable AI assistant into a customizable automation platform that can integrate with virtually any tool, service, or data source in your development workflow.<\/p>\n\n<p>This comprehensive technical guide explores the architecture, protocols, and best practices for building robust MCP extensions for goose. Whether you're integrating with existing services, exposing proprietary data sources, or creating entirely new AI-powered workflows, understanding MCP's architecture is essential for advanced goose usage.<\/p>\n\n<h2>\n  \n  \n  Understanding the Model Context Protocol (MCP)\n<\/h2>\n\n<h3>\n  \n  \n  What is MCP?\n<\/h3>\n\n<p>The Model Context Protocol (MCP) follows a client-host-server architecture where each host can run multiple client instances, built on <em>JSON-RPC<\/em>, providing a stateful session protocol focused on context exchange and sampling coordination between clients and servers.<\/p>\n\n<p>Think of MCP as the <em>\"USB-C\"<\/em> of AI integrations; a universal protocol that standardizes how AI systems connect to external tools and data sources. <em>Before MCP, developers had to build custom connectors for each integration, leading to fragmented, unmaintainable code<\/em>. MCP provides a universal, open standard for connecting AI systems with data sources, replacing fragmented integrations with a single protocol.<\/p>\n\n<h3>\n  \n  \n  Why MCP Matters for goose\n<\/h3>\n\n<p>goose implements MCP as its extension system, which means:<\/p>\n\n<ol>\n<li>\n<strong>Interoperability<\/strong>: Extensions built for Goose work with other MCP-compatible clients (Claude Desktop, Cursor, Cline)<\/li>\n<li>\n<strong>Standardization<\/strong>: Clear, documented protocols for building integrations<\/li>\n<li>\n<strong>Security<\/strong>: Well-defined boundaries and capability negotiation<\/li>\n<li>\n<strong>Ecosystem<\/strong>: Access to a growing library of MCP servers<\/li>\n<li>\n<strong>Future-proof<\/strong>: As MCP evolves, Goose benefits from protocol improvements<\/li>\n<\/ol>\n\n<h3>\n  \n  \n  MCP Architecture Overview\n<\/h3>\n\n<p>The architecture consists of three core components: hosts (the container and coordinator), clients (connecting to servers), and servers (exposing resources, tools, and prompts via MCP primitives).<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502     Goose Host Process              \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502   Goose Application (Host)     \u2502 \u2502\n\u2502  \u2502                                \u2502 \u2502\n\u2502  \u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502 \u2502\n\u2502  \u2502  \u2502 Client 1 \u2502  \u2502 Client 2 \u2502  \u2502 \u2502\n\u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2518  \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n           \u2502             \u2502\n           \u25bc             \u25bc\n    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n    \u2502 Server 1 \u2502  \u2502 Server 2 \u2502\n    \u2502(Filesystem)  \u2502(Database)\u2502\n    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Host (goose Application)\n<\/h4>\n\n<ul>\n<li>Creates and manages multiple client instances<\/li>\n<li>Coordinates LLM interactions<\/li>\n<li>Presents unified interface to users<\/li>\n<li>Handles authentication and security boundaries<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Clients\n<\/h4>\n\n<ul>\n<li>Maintain 1:1 connection with specific servers<\/li>\n<li>Handle protocol communication<\/li>\n<li>Manage capability negotiation<\/li>\n<li>Route messages between host and server<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Servers (Extensions)\n<\/h4>\n\n<ul>\n<li>Expose tools, resources, and prompts<\/li>\n<li>Implement specific functionality (file access, API calls, database queries)<\/li>\n<li>Operate independently with focused responsibilities<\/li>\n<li>Handle authentication with external services<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  MCP Core Concepts\n<\/h2>\n\n<h3>\n  \n  \n  1. Primitives\n<\/h3>\n\n<p>The Building Blocks<br>\nMCP defines three fundamental primitives that servers expose to clients:<\/p>\n\n<p><strong>Prompts<\/strong><br>\nPrompts allow servers to provide structured messages and instructions for interacting with language models, where clients can discover available prompts, retrieve their contents, and provide arguments to customize them.<\/p>\n\n<p><strong>Use Cases:<\/strong><\/p>\n\n<ul>\n<li>Pre-defined task templates<\/li>\n<li>Workflow orchestration<\/li>\n<li>Guided interactions<\/li>\n<li>Domain-specific instructions<\/li>\n<\/ul>\n\n<p><strong>Example<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"name\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"code_review\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"description\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"Comprehensive code review prompt\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"arguments\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"w\">\n    <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"name\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"language\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"description\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"Programming language\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"required\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"kc\">true<\/span><span class=\"w\">\n    <\/span><span class=\"p\">},<\/span><span class=\"w\">\n    <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"name\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"focus_area\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"description\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"Specific area to review (security, performance, style)\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"required\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"kc\">false<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">]<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Resources<\/strong><br>\nResources represent structured data or content that provides context to the AI model.<\/p>\n\n<p><strong>Characteristics<\/strong><\/p>\n\n<ul>\n<li>URI-addressable (e.g., <code>file:\/\/\/path\/to\/file<\/code>, <code>postgres:\/\/db\/table<\/code>)<\/li>\n<li>Can be text, binary, or structured data<\/li>\n<li>Support subscription for real-time updates<\/li>\n<li>Provide metadata and MIME types<\/li>\n<\/ul>\n\n<p><strong>Use Case<\/strong><\/p>\n\n<ul>\n<li>File system access<\/li>\n<li>Database records<\/li>\n<li>API responses<\/li>\n<li>Configuration data<\/li>\n<li>Documentation<\/li>\n<\/ul>\n\n<p><strong>Example<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"uri\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"file:\/\/\/project\/src\/auth.ts\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"name\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"Authentication Module\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"description\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"User authentication logic\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"mimeType\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"text\/x-typescript\"<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Tools<\/strong><br>\nTools are executable functions that allow the AI model to perform actions or retrieve information.<\/p>\n\n<p><strong>Characteristics<\/strong><\/p>\n\n<ul>\n<li>Defined input\/output schemas (JSON Schema)<\/li>\n<li>Can be marked as readOnly or destructive<\/li>\n<li>Return structured data or error messages<\/li>\n<li>Support streaming responses<\/li>\n<\/ul>\n\n<p><strong>Use Cases<\/strong><\/p>\n\n<ul>\n<li>Execute commands<\/li>\n<li>Make API calls<\/li>\n<li>Query databases<\/li>\n<li>Modify files<\/li>\n<li>Run tests<\/li>\n<\/ul>\n\n<p><strong>Example<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"name\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"execute_sql_query\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"description\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"Execute SQL query against database\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"inputSchema\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"type\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"object\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"properties\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"query\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n        <\/span><span class=\"nl\">\"type\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"string\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n        <\/span><span class=\"nl\">\"description\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"SQL query to execute\"<\/span><span class=\"w\">\n      <\/span><span class=\"p\">},<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"database\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n        <\/span><span class=\"nl\">\"type\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"string\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n        <\/span><span class=\"nl\">\"description\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"Database name\"<\/span><span class=\"w\">\n      <\/span><span class=\"p\">}<\/span><span class=\"w\">\n    <\/span><span class=\"p\">},<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"required\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"s2\">\"query\"<\/span><span class=\"p\">]<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  2. Message Types\n<\/h3>\n\n<p>MCP uses JSON-RPC 2.0 for all client-server communication, defining three fundamental message types: requests (bidirectional messages expecting responses), responses (successful results or error messages), and notifications (one-way messages requiring no response).<\/p>\n\n<p><strong>Request\/Response Pattern<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"err\">\/\/<\/span><span class=\"w\"> <\/span><span class=\"err\">Request<\/span><span class=\"w\">\n<\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"jsonrpc\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2.0\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"id\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"method\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"tools\/call\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"params\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"name\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"read_file\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"arguments\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"path\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"\/path\/to\/file.txt\"<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n\n<\/span><span class=\"err\">\/\/<\/span><span class=\"w\"> <\/span><span class=\"err\">Response<\/span><span class=\"w\">\n<\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"jsonrpc\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2.0\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"id\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"result\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"content\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"w\">\n      <\/span><span class=\"p\">{<\/span><span class=\"w\">\n        <\/span><span class=\"nl\">\"type\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"text\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n        <\/span><span class=\"nl\">\"text\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"File contents here...\"<\/span><span class=\"w\">\n      <\/span><span class=\"p\">}<\/span><span class=\"w\">\n    <\/span><span class=\"p\">]<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Notification Pattern<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"jsonrpc\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2.0\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"method\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"notifications\/resources\/updated\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"params\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"uri\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"file:\/\/\/project\/package.json\"<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  3. Capability Negotiation\n<\/h3>\n\n<p>MCP uses a capability-based negotiation system where clients and servers explicitly declare their supported features during initialization, with servers declaring capabilities like resource subscriptions, tool support, and prompt templates, while clients declare capabilities like sampling support and notification handling.<\/p>\n\n<p><strong>Server Capability Declaration<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"capabilities\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"resources\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"subscribe\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"kc\">true<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"listChanged\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"kc\">true<\/span><span class=\"w\">\n    <\/span><span class=\"p\">},<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"tools\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"listChanged\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"kc\">true<\/span><span class=\"w\">\n    <\/span><span class=\"p\">},<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"prompts\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"listChanged\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"kc\">true<\/span><span class=\"w\">\n    <\/span><span class=\"p\">},<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"logging\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Client Capability Declaration<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"capabilities\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"roots\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"listChanged\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"kc\">true<\/span><span class=\"w\">\n    <\/span><span class=\"p\">},<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"sampling\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Why Capability Negotiation Matters\n<\/h4>\n\n<ul>\n<li>Enables graceful feature detection<\/li>\n<li>Allows protocol evolution without breaking changes<\/li>\n<li>Provides clear contract between client and server<\/li>\n<li>Enables clients to adapt behavior based on server capabilities<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  4. Connection Lifecycle\n<\/h3>\n\n<p>Every MCP session follows a defined lifecycle<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Initialize  \u2502 \u25c4\u2500\u2500 Capability negotiation\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502\n       \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Active     \u2502 \u25c4\u2500\u2500 Normal operation (requests\/responses\/notifications)\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502\n       \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Shutdown   \u2502 \u25c4\u2500\u2500 Graceful termination\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>1. Initialization Phase<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"err\">\/\/<\/span><span class=\"w\"> <\/span><span class=\"err\">Client<\/span><span class=\"w\"> <\/span><span class=\"err\">sends<\/span><span class=\"w\"> <\/span><span class=\"err\">initialize<\/span><span class=\"w\"> <\/span><span class=\"err\">request<\/span><span class=\"w\">\n<\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"jsonrpc\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2.0\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"id\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"method\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"initialize\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"params\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"protocolVersion\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2024-11-05\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"capabilities\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"err\">\/*<\/span><span class=\"w\"> <\/span><span class=\"err\">client<\/span><span class=\"w\"> <\/span><span class=\"err\">capabilities<\/span><span class=\"w\"> <\/span><span class=\"err\">*\/<\/span><span class=\"w\"> <\/span><span class=\"p\">},<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"clientInfo\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"name\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"goose\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"version\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"1.0.0\"<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n\n<\/span><span class=\"err\">\/\/<\/span><span class=\"w\"> <\/span><span class=\"err\">Server<\/span><span class=\"w\"> <\/span><span class=\"err\">responds<\/span><span class=\"w\"> <\/span><span class=\"err\">with<\/span><span class=\"w\"> <\/span><span class=\"err\">capabilities<\/span><span class=\"w\">\n<\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"jsonrpc\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2.0\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"id\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"result\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"protocolVersion\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2024-11-05\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"capabilities\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"err\">\/*<\/span><span class=\"w\"> <\/span><span class=\"err\">server<\/span><span class=\"w\"> <\/span><span class=\"err\">capabilities<\/span><span class=\"w\"> <\/span><span class=\"err\">*\/<\/span><span class=\"w\"> <\/span><span class=\"p\">},<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"serverInfo\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"name\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"filesystem-server\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n      <\/span><span class=\"nl\">\"version\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"1.0.0\"<\/span><span class=\"w\">\n    <\/span><span class=\"p\">}<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n\n<\/span><span class=\"err\">\/\/<\/span><span class=\"w\"> <\/span><span class=\"err\">Client<\/span><span class=\"w\"> <\/span><span class=\"err\">sends<\/span><span class=\"w\"> <\/span><span class=\"err\">initialized<\/span><span class=\"w\"> <\/span><span class=\"err\">notification<\/span><span class=\"w\">\n<\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"jsonrpc\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2.0\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"method\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"notifications\/initialized\"<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<ol>\n<li><strong>Active Phase<\/strong><\/li>\n<\/ol>\n\n<ul>\n<li>Clients make tool calls, retrieve resources, fetch prompts<\/li>\n<li>Servers send notifications (resource updates, log messages)<\/li>\n<li>Both parties respect declared capabilities<\/li>\n<\/ul>\n\n<ol>\n<li>\n<strong>Shutdown Phase<\/strong>\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"err\">\/\/<\/span><span class=\"w\"> <\/span><span class=\"err\">Client<\/span><span class=\"w\"> <\/span><span class=\"err\">sends<\/span><span class=\"w\"> <\/span><span class=\"err\">shutdown<\/span><span class=\"w\"> <\/span><span class=\"err\">request<\/span><span class=\"w\"> <\/span><span class=\"err\">(optional)<\/span><span class=\"w\">\n<\/span><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"jsonrpc\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"2.0\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"id\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">999<\/span><span class=\"p\">,<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"method\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"shutdown\"<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n\n<\/span><span class=\"err\">\/\/<\/span><span class=\"w\"> <\/span><span class=\"err\">Connection<\/span><span class=\"w\"> <\/span><span class=\"err\">closes<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  5. Transport Mechanisms\n<\/h3>\n\n<p>MCP supports two primary transport mechanisms:<\/p>\n\n<h4>\n  \n  \n  STDIO (Standard Input\/Output)\n<\/h4>\n\n<p>Used for local servers running as separate processes.<\/p>\n\n<p><strong>Characteristics<\/strong><\/p>\n\n<ul>\n<li>Process-based communication<\/li>\n<li>Stdin for requests, stdout for responses<\/li>\n<li>Stderr for logging<\/li>\n<li>Simple, efficient for local integrations<\/li>\n<\/ul>\n\n<p><strong>When to Use<\/strong><\/p>\n\n<ul>\n<li>Local development tools<\/li>\n<li>File system access<\/li>\n<li>Database connections<\/li>\n<li>Command-line utilities<\/li>\n<\/ul>\n\n<p><strong>goose Configuration<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">filesystem<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uv\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">run\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">mcp-filesystem\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  SSE (Server-Sent Events over HTTP)\n<\/h4>\n\n<p>Used for remote servers accessed over HTTP\/HTTPS.<\/p>\n\n<p><strong>Characteristics<\/strong><\/p>\n\n<ul>\n<li>HTTP-based communication<\/li>\n<li>Long-lived connections<\/li>\n<li>Supports webhooks for notifications<\/li>\n<li>Suitable for hosted services<\/li>\n<\/ul>\n\n<p><strong>When to Use<\/strong><\/p>\n\n<ul>\n<li>Remote APIs<\/li>\n<li>Cloud services<\/li>\n<li>Multi-user scenarios<\/li>\n<li>Centralized deployments<\/li>\n<\/ul>\n\n<p><strong>goose Configuration<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">remote_api<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">sse<\/span>\n    <span class=\"na\">url<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">https:\/\/api.example.com\/mcp\"<\/span>\n    <span class=\"na\">headers<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">Authorization<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">Bearer<\/span><span class=\"nv\"> <\/span><span class=\"s\">${API_TOKEN}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  goose's Extension Architecture\n<\/h2>\n\n<h3>\n  \n  \n  How goose Implements MCP\n<\/h3>\n\n<p>goose acts as both an MCP host and manages multiple MCP clients, with each extension running as a separate MCP server. All of <a href=\"https:\/\/block.github.io\/goose\/docs\/tutorials\/custom-extensions\/\" rel=\"noopener noreferrer\">goose's built-in extensions<\/a> are MCP servers in their own right, and if you'd like to use the MCP servers included with goose with any other agent, you are free to do so.<\/p>\n\n<h4>\n  \n  \n  Extension Categories in goose\n<\/h4>\n\n<p><strong>1. Built-in Extensions<\/strong>: Shipped with goose<\/p>\n\n<ul>\n<li>Developer tools<\/li>\n<li>File system operations<\/li>\n<li>Screen capture<\/li>\n<li>Computer control<\/li>\n<\/ul>\n\n<p><strong>2. Remote Extensions<\/strong>: From MCP server directory<\/p>\n\n<ul>\n<li>GitHub integration<\/li>\n<li>Slack connector<\/li>\n<li>Database adapters<\/li>\n<li>API wrappers<\/li>\n<\/ul>\n\n<p><strong>3. Custom Extensions<\/strong>: Your own MCP servers<\/p>\n\n<ul>\n<li>Proprietary tools<\/li>\n<li>Internal APIs<\/li>\n<li>Domain-specific integrations<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Extension Configuration\n<\/h4>\n\n<p>Extensions are configured in <code>~\/.config\/goose\/config.yaml<\/code>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">providers<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">openai<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">model<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gpt-4o<\/span>\n    <span class=\"na\">api_key_env<\/span><span class=\"pi\">:<\/span> <span class=\"s\">OPENAI_API_KEY<\/span>\n\n<span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"c1\"># Built-in extension<\/span>\n  <span class=\"na\">developer<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">enabled<\/span><span class=\"pi\">:<\/span> <span class=\"kc\">true<\/span>\n\n  <span class=\"c1\"># Command-line extension (STDIO)<\/span>\n  <span class=\"na\">github<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">npx\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">-y\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">@modelcontextprotocol\/server-github\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">GITHUB_TOKEN<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${GITHUB_TOKEN}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n\n  <span class=\"c1\"># Remote extension (SSE)<\/span>\n  <span class=\"na\">custom_api<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">sse<\/span>\n    <span class=\"na\">url<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">https:\/\/mcp.company.com\/api\"<\/span>\n    <span class=\"na\">headers<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">Authorization<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">Bearer<\/span><span class=\"nv\"> <\/span><span class=\"s\">${API_KEY}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n\n  <span class=\"c1\"># Local Python extension<\/span>\n  <span class=\"na\">database_tools<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uv\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">run\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">\/path\/to\/db-tools\/.venv\/bin\/db-mcp\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">DATABASE_URL<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${DATABASE_URL}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">600<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Managing Extensions\n<\/h4>\n\n<p><em><strong>Via CLI<\/strong><\/em><br>\nExtensions can be managed through the CLI using the goose configure command.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Open configuration wizard<\/span>\ngoose configure\n\n<span class=\"c\"># Select \"Add Extension\"<\/span>\n<span class=\"c\"># Choose extension type:<\/span>\n<span class=\"c\">#   - Command-line Extension (STDIO)<\/span>\n<span class=\"c\">#   - Remote Extension (SSE)<\/span>\n<span class=\"c\">#   - From Directory (pre-built servers)<\/span>\n\n<span class=\"c\"># Example: Adding Wikipedia reader<\/span>\ngoose configure\n<span class=\"o\">&gt;<\/span> Add Extension\n<span class=\"o\">&gt;<\/span> Command-line Extension\n<span class=\"o\">&gt;<\/span> Name: Wikipedia Reader\n<span class=\"o\">&gt;<\/span> Command: uvx mcp-wiki\n<span class=\"o\">&gt;<\/span> Timeout: 300\n<span class=\"o\">&gt;<\/span> Environment variables? No\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Via Desktop UI\n<\/h4>\n\n<p>In the desktop interface, click the button in the top-left to open the sidebar, click the Extensions button, and under Extensions, click Add custom extension.<\/p>\n\n<p><strong>Steps:<\/strong><\/p>\n\n<ol>\n<li>Open sidebar \u2192 Extensions<\/li>\n<li>Click \"Add custom extension\"<\/li>\n<li>Fill in details:<\/li>\n<\/ol>\n\n<ul>\n<li> Name<\/li>\n<li> Description<\/li>\n<li> Type (STDIO\/SSE)<\/li>\n<li> Command\/URL<\/li>\n<li> Environment variables<\/li>\n<li> Timeout<\/li>\n<\/ul>\n\n<ol>\n<li>Toggle extension on\/off<\/li>\n<li>View available tools<\/li>\n<\/ol>\n\n<h4>\n  \n  \n  Deep Link Protocol\n<\/h4>\n\n<p>Extensions can be installed using goose's deep link protocol, with URL format varying based on the extension type:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>goose:\/\/extension?cmd=npx&amp;arg=-y&amp;arg=@modelcontextprotocol\/server-github&amp;timeout=300&amp;id=github&amp;name=GitHub&amp;description=GitHub%20integration\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<blockquote>\n<p>This enables one-click installation from web pages, documentation, or sharing links.<\/p>\n<\/blockquote>\n\n<h2>\n  \n  \n  Building Custom MCP Extensions\n<\/h2>\n\n<h3>\n  \n  \n  Development Workflow\n<\/h3>\n\n<p>The process for building <a href=\"https:\/\/block.github.io\/goose\/docs\/tutorials\/custom-extensions\/\" rel=\"noopener noreferrer\">custom extensions<\/a> involves initializing a project using uv, implementing the MCP server code, defining project configuration in <code>pyproject.toml<\/code>, testing with MCP Inspector, and integrating with goose.<br>\n<em>Let's build a practical example: a PostgreSQL database explorer extension.<\/em><\/p>\n\n<p><em><strong>Example: PostgreSQL MCP Server<\/strong><\/em><br>\n<strong>Step 1: Project Setup<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Initialize project<\/span>\nuv init <span class=\"nt\">--lib<\/span> mcp-postgres\n<span class=\"nb\">cd <\/span>mcp-postgres\n\n<span class=\"c\"># Create directory structure<\/span>\n<span class=\"nb\">mkdir<\/span> <span class=\"nt\">-p<\/span> src\/mcp_postgres\n<span class=\"nb\">touch <\/span>src\/mcp_postgres\/server.py\n<span class=\"nb\">touch <\/span>src\/mcp_postgres\/__main__.py\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Project Structure<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>mcp-postgres\/\n\u251c\u2500\u2500 README.md\n\u251c\u2500\u2500 pyproject.toml\n\u251c\u2500\u2500 src\/\n\u2502   \u2514\u2500\u2500 mcp_postgres\/\n\u2502       \u251c\u2500\u2500 __init__.py      # CLI entry point\n\u2502       \u251c\u2500\u2500 __main__.py      # Module execution\n\u2502       \u251c\u2500\u2500 server.py        # MCP server implementation\n\u2502       \u2514\u2500\u2500 py.typed         # Type hints marker\n\u2514\u2500\u2500 uv.lock\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Step 2: Implement Server Logic<\/strong><br>\n<code>src\/mcp_postgres\/server.py<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">os<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">psycopg2<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">typing<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">List<\/span><span class=\"p\">,<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">,<\/span> <span class=\"n\">Any<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">mcp.server.fastmcp<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">FastMCP<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">mcp.shared.exceptions<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">McpError<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">mcp.types<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">ErrorData<\/span><span class=\"p\">,<\/span> <span class=\"n\">INTERNAL_ERROR<\/span><span class=\"p\">,<\/span> <span class=\"n\">INVALID_PARAMS<\/span>\n\n<span class=\"c1\"># Initialize MCP server\n<\/span><span class=\"n\">mcp<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">FastMCP<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">postgres-explorer<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">get_connection<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Get database connection from environment<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">db_url<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">DATABASE_URL<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">db_url<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span>\n            <span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span>\n                <span class=\"n\">INVALID_PARAMS<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">DATABASE_URL environment variable not set<\/span><span class=\"sh\">\"<\/span>\n            <span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span>\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">psycopg2<\/span><span class=\"p\">.<\/span><span class=\"nf\">connect<\/span><span class=\"p\">(<\/span><span class=\"n\">db_url<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span>\n            <span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span><span class=\"n\">INTERNAL_ERROR<\/span><span class=\"p\">,<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Database connection failed: <\/span><span class=\"si\">{<\/span><span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span> <span class=\"k\">from<\/span> <span class=\"n\">e<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">list_tables<\/span><span class=\"p\">(<\/span><span class=\"n\">schema<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">public<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">List<\/span><span class=\"p\">[<\/span><span class=\"n\">Dict<\/span><span class=\"p\">[<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"nb\">str<\/span><span class=\"p\">]]:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n    List all tables in the specified schema.\n\n    Args:\n        schema: Database schema name (default: public)\n\n    Returns:\n        List of tables with names and descriptions\n    <\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">conn<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_connection<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">with<\/span> <span class=\"n\">conn<\/span><span class=\"p\">.<\/span><span class=\"nf\">cursor<\/span><span class=\"p\">()<\/span> <span class=\"k\">as<\/span> <span class=\"n\">cur<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"nf\">execute<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n                SELECT \n                    table_name,\n                    obj_description((table_schema||<\/span><span class=\"sh\">'<\/span><span class=\"s\">.<\/span><span class=\"sh\">'<\/span><span class=\"s\">||table_name)::regclass) as description\n                FROM information_schema.tables\n                WHERE table_schema = %s\n                ORDER BY table_name\n            <\/span><span class=\"sh\">\"\"\"<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"n\">schema<\/span><span class=\"p\">,))<\/span>\n\n            <span class=\"n\">results<\/span> <span class=\"o\">=<\/span> <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"n\">execute<\/span><span class=\"p\">.<\/span><span class=\"nf\">fetchall<\/span><span class=\"p\">()<\/span>\n            <span class=\"k\">return<\/span> <span class=\"p\">[<\/span>\n                <span class=\"p\">{<\/span>\n                    <span class=\"sh\">\"<\/span><span class=\"s\">table_name<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">],<\/span>\n                    <span class=\"sh\">\"<\/span><span class=\"s\">description<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"ow\">or<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">No description<\/span><span class=\"sh\">\"<\/span>\n                <span class=\"p\">}<\/span>\n                <span class=\"k\">for<\/span> <span class=\"n\">row<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">results<\/span>\n            <span class=\"p\">]<\/span>\n    <span class=\"k\">finally<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">conn<\/span><span class=\"p\">.<\/span><span class=\"nf\">close<\/span><span class=\"p\">()<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">describe_table<\/span><span class=\"p\">(<\/span><span class=\"n\">table_name<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">schema<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">public<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">[<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">Any<\/span><span class=\"p\">]:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n    Get detailed schema information for a table.\n\n    Args:\n        table_name: Name of the table\n        schema: Database schema (default: public)\n\n    Returns:\n        Table schema including columns, types, and constraints\n    <\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">conn<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_connection<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">with<\/span> <span class=\"n\">conn<\/span><span class=\"p\">.<\/span><span class=\"nf\">cursor<\/span><span class=\"p\">()<\/span> <span class=\"k\">as<\/span> <span class=\"n\">cur<\/span><span class=\"p\">:<\/span>\n            <span class=\"c1\"># Get column information\n<\/span>            <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"nf\">execute<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n                SELECT \n                    column_name,\n                    data_type,\n                    character_maximum_length,\n                    is_nullable,\n                    column_default\n                FROM information_schema.columns\n                WHERE table_schema = %s AND table_name = %s\n                ORDER BY ordinal_position\n            <\/span><span class=\"sh\">\"\"\"<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"n\">schema<\/span><span class=\"p\">,<\/span> <span class=\"n\">table_name<\/span><span class=\"p\">))<\/span>\n\n            <span class=\"n\">columns<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n                <span class=\"p\">{<\/span>\n                    <span class=\"sh\">\"<\/span><span class=\"s\">name<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">],<\/span>\n                    <span class=\"sh\">\"<\/span><span class=\"s\">type<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">],<\/span>\n                    <span class=\"sh\">\"<\/span><span class=\"s\">max_length<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">2<\/span><span class=\"p\">],<\/span>\n                    <span class=\"sh\">\"<\/span><span class=\"s\">nullable<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">3<\/span><span class=\"p\">]<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">YES<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n                    <span class=\"sh\">\"<\/span><span class=\"s\">default<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">4<\/span><span class=\"p\">]<\/span>\n                <span class=\"p\">}<\/span>\n                <span class=\"k\">for<\/span> <span class=\"n\">row<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"nf\">fetchall<\/span><span class=\"p\">()<\/span>\n            <span class=\"p\">]<\/span>\n\n            <span class=\"c1\"># Get primary key\n<\/span>            <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"nf\">execute<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n                SELECT column_name\n                FROM information_schema.key_column_usage\n                WHERE table_schema = %s \n                  AND table_name = %s\n                  AND constraint_name LIKE <\/span><span class=\"sh\">'<\/span><span class=\"s\">%_pkey<\/span><span class=\"sh\">'<\/span><span class=\"s\">\n            <\/span><span class=\"sh\">\"\"\"<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"n\">schema<\/span><span class=\"p\">,<\/span> <span class=\"n\">table_name<\/span><span class=\"p\">))<\/span>\n\n            <span class=\"n\">primary_keys<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"k\">for<\/span> <span class=\"n\">row<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"nf\">fetchall<\/span><span class=\"p\">()]<\/span>\n\n            <span class=\"c1\"># Get indexes\n<\/span>            <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"nf\">execute<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n                SELECT indexname, indexdef\n                FROM pg_indexes\n                WHERE schemaname = %s AND tablename = %s\n            <\/span><span class=\"sh\">\"\"\"<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"n\">schema<\/span><span class=\"p\">,<\/span> <span class=\"n\">table_name<\/span><span class=\"p\">))<\/span>\n\n            <span class=\"n\">indexes<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n                <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">name<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">],<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">definition<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">row<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]}<\/span>\n                <span class=\"k\">for<\/span> <span class=\"n\">row<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"nf\">fetchall<\/span><span class=\"p\">()<\/span>\n            <span class=\"p\">]<\/span>\n\n            <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">table_name<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">table_name<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">schema<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">schema<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">columns<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">columns<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">primary_keys<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">primary_keys<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">indexes<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">indexes<\/span>\n            <span class=\"p\">}<\/span>\n    <span class=\"k\">finally<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">conn<\/span><span class=\"p\">.<\/span><span class=\"nf\">close<\/span><span class=\"p\">()<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">(<\/span><span class=\"n\">annotations<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">readOnly<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"bp\">False<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">destructive<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"bp\">False<\/span><span class=\"p\">})<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">execute_query<\/span><span class=\"p\">(<\/span><span class=\"n\">query<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">limit<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">100<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">[<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">Any<\/span><span class=\"p\">]:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n    Execute a SELECT query against the database.\n\n    Args:\n        query: SQL SELECT statement\n        limit: Maximum number of rows to return (default: 100)\n\n    Returns:\n        Query results with column names and data\n    <\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"c1\"># Validate query is SELECT only\n<\/span>    <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">query<\/span><span class=\"p\">.<\/span><span class=\"nf\">strip<\/span><span class=\"p\">().<\/span><span class=\"nf\">upper<\/span><span class=\"p\">().<\/span><span class=\"nf\">startswith<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">SELECT<\/span><span class=\"sh\">\"<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span>\n            <span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span>\n                <span class=\"n\">INVALID_PARAMS<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">Only SELECT queries are allowed<\/span><span class=\"sh\">\"<\/span>\n            <span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span>\n\n    <span class=\"n\">conn<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_connection<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">with<\/span> <span class=\"n\">conn<\/span><span class=\"p\">.<\/span><span class=\"nf\">cursor<\/span><span class=\"p\">()<\/span> <span class=\"k\">as<\/span> <span class=\"n\">cur<\/span><span class=\"p\">:<\/span>\n            <span class=\"c1\"># Add LIMIT if not present\n<\/span>            <span class=\"k\">if<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">LIMIT<\/span><span class=\"sh\">\"<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">query<\/span><span class=\"p\">.<\/span><span class=\"nf\">upper<\/span><span class=\"p\">():<\/span>\n                <span class=\"n\">query<\/span> <span class=\"o\">=<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">query<\/span><span class=\"si\">}<\/span><span class=\"s\"> LIMIT <\/span><span class=\"si\">{<\/span><span class=\"n\">limit<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span>\n\n            <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"nf\">execute<\/span><span class=\"p\">(<\/span><span class=\"n\">query<\/span><span class=\"p\">)<\/span>\n\n            <span class=\"c1\"># Get column names\n<\/span>            <span class=\"n\">columns<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">desc<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"k\">for<\/span> <span class=\"n\">desc<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"n\">description<\/span><span class=\"p\">]<\/span>\n\n            <span class=\"c1\"># Fetch results\n<\/span>            <span class=\"n\">rows<\/span> <span class=\"o\">=<\/span> <span class=\"n\">cur<\/span><span class=\"p\">.<\/span><span class=\"nf\">fetchall<\/span><span class=\"p\">()<\/span>\n\n            <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">columns<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">columns<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">rows<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n                    <span class=\"nf\">dict<\/span><span class=\"p\">(<\/span><span class=\"nf\">zip<\/span><span class=\"p\">(<\/span><span class=\"n\">columns<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">))<\/span>\n                    <span class=\"k\">for<\/span> <span class=\"n\">row<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">rows<\/span>\n                <span class=\"p\">],<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">row_count<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">rows<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">}<\/span>\n    <span class=\"k\">finally<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">conn<\/span><span class=\"p\">.<\/span><span class=\"nf\">close<\/span><span class=\"p\">()<\/span>\n\n<span class=\"nd\">@mcp.resource<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">postgres:\/\/schemas\/{schema}\/tables<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">get_schema_tables<\/span><span class=\"p\">(<\/span><span class=\"n\">schema<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Resource providing list of tables in a schema<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">tables<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">list_tables<\/span><span class=\"p\">(<\/span><span class=\"n\">schema<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"sh\">\"<\/span><span class=\"se\">\\n<\/span><span class=\"sh\">\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">join<\/span><span class=\"p\">([<\/span>\n        <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">- <\/span><span class=\"si\">{<\/span><span class=\"n\">t<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">table_name<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span><span class=\"si\">}<\/span><span class=\"s\">: <\/span><span class=\"si\">{<\/span><span class=\"n\">t<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">description<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span>\n        <span class=\"k\">for<\/span> <span class=\"n\">t<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">tables<\/span>\n    <span class=\"p\">])<\/span>\n\n<span class=\"nd\">@mcp.prompt<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">query_optimizer_prompt<\/span><span class=\"p\">(<\/span><span class=\"n\">query<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Prompt for optimizing SQL queries<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">return<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">Analyze and optimize this SQL query:\n<\/span><\/code><\/pre>\n\n<\/div>\n\n<p><br>\nsql<br>\n{query}<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\nProvide:\n1. Performance analysis\n2. Index recommendations\n3. Query plan explanation\n4. Optimized version\n\nConsider:\n- Join efficiency\n- Index usage\n- Subquery optimization\n- N+1 query problems\n\"\"\"\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>src\/mcp_postgres\/__init__.py<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">argparse<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">os<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">.server<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">mcp<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">main<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">MCP PostgreSQL Explorer<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">parser<\/span> <span class=\"o\">=<\/span> <span class=\"n\">argparse<\/span><span class=\"p\">.<\/span><span class=\"nc\">ArgumentParser<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">description<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">PostgreSQL database explorer for MCP<\/span><span class=\"sh\">\"<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"n\">parser<\/span><span class=\"p\">.<\/span><span class=\"nf\">add_argument<\/span><span class=\"p\">(<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">--database-url<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">help<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">PostgreSQL connection URL (or set DATABASE_URL env var)<\/span><span class=\"sh\">\"<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"n\">args<\/span> <span class=\"o\">=<\/span> <span class=\"n\">parser<\/span><span class=\"p\">.<\/span><span class=\"nf\">parse_args<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"n\">args<\/span><span class=\"p\">.<\/span><span class=\"n\">database_url<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"n\">environ<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">DATABASE_URL<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">args<\/span><span class=\"p\">.<\/span><span class=\"n\">database_url<\/span>\n\n    <span class=\"n\">mcp<\/span><span class=\"p\">.<\/span><span class=\"nf\">run<\/span><span class=\"p\">()<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"n\">__name__<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">__main__<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span>\n    <span class=\"nf\">main<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>src\/mcp_postgres\/__main__.py<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">mcp_postgres<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">main<\/span>\n<span class=\"nf\">main<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Step 3: Configure Project<\/strong><br>\n<code>pyproject.toml<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight toml\"><code><span class=\"nn\">[project]<\/span>\n<span class=\"py\">name<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"mcp-postgres\"<\/span>\n<span class=\"py\">version<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"0.1.0\"<\/span>\n<span class=\"py\">description<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"PostgreSQL explorer MCP server\"<\/span>\n<span class=\"py\">readme<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"README.md\"<\/span>\n<span class=\"py\">requires-python<\/span> <span class=\"p\">=<\/span> <span class=\"py\">\"&gt;<\/span><span class=\"p\">=<\/span><span class=\"mf\">3.10<\/span><span class=\"s\">\"<\/span><span class=\"err\">\n<\/span><span class=\"py\">dependencies<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"py\">\"mcp[cli]&gt;<\/span><span class=\"p\">=<\/span><span class=\"mf\">1.2<\/span><span class=\"err\">.<\/span><span class=\"mi\">0<\/span><span class=\"s\">\",<\/span><span class=\"err\">\n<\/span>    <span class=\"py\">\"psycopg2-binary&gt;<\/span><span class=\"p\">=<\/span><span class=\"mf\">2.9<\/span><span class=\"err\">.<\/span><span class=\"mi\">9<\/span><span class=\"s\">\",<\/span><span class=\"err\">\n<\/span><span class=\"p\">]<\/span>\n\n<span class=\"nn\">[project.scripts]<\/span>\n<span class=\"py\">mcp-postgres<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"mcp_postgres:main\"<\/span>\n\n<span class=\"nn\">[project.optional-dependencies]<\/span>\n<span class=\"py\">dev<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"py\">\"pytest&gt;<\/span><span class=\"p\">=<\/span><span class=\"mf\">7.4<\/span><span class=\"err\">.<\/span><span class=\"mi\">0<\/span><span class=\"s\">\",<\/span><span class=\"err\">\n<\/span>    <span class=\"py\">\"pytest-asyncio&gt;<\/span><span class=\"p\">=<\/span><span class=\"mf\">0.21<\/span><span class=\"err\">.<\/span><span class=\"mi\">0<\/span><span class=\"s\">\",<\/span><span class=\"err\">\n<\/span><span class=\"p\">]<\/span>\n\n<span class=\"nn\">[build-system]<\/span>\n<span class=\"py\">requires<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span><span class=\"s\">\"hatchling\"<\/span><span class=\"p\">]<\/span>\n<span class=\"py\">build-backend<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"hatchling.build\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Step 4: Test with MCP Inspector<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Install dependencies<\/span>\nuv <span class=\"nb\">sync<\/span>\n\n<span class=\"c\"># Activate virtual environment<\/span>\n<span class=\"nb\">source<\/span> .venv\/bin\/activate\n\n<span class=\"c\"># Run in development mode<\/span>\nmcp dev src\/mcp_postgres\/server.py\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Open <code>http:\/\/localhost:5173<\/code> in your browser:<\/p>\n\n<ol>\n<li>Click \"Connect\" to initialize server<\/li>\n<li>Navigate to \"Tools\" tab<\/li>\n<li>Click \"List Tools\" to see available tools<\/li>\n<li>Test each tool with sample inputs<\/li>\n<li>Check \"Resources\" tab for available resources<\/li>\n<li>Test \"Prompts\" tab for defined prompts<\/li>\n<\/ol>\n\n<p><strong>Testing CLI<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Install locally<\/span>\nuv pip <span class=\"nb\">install<\/span> <span class=\"nb\">.<\/span>\n\n<span class=\"c\"># Verify installation<\/span>\n<span class=\"nb\">ls<\/span> .venv\/bin\/  <span class=\"c\"># Should see mcp-postgres<\/span>\n\n<span class=\"c\"># Test help<\/span>\nmcp-postgres <span class=\"nt\">--help<\/span>\n\n<span class=\"c\"># Test with database URL<\/span>\n<span class=\"nv\">DATABASE_URL<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"postgresql:\/\/user:pass@localhost\/dbname\"<\/span> mcp-postgres\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Step 5: Integrate with goose<\/strong><br>\n<em><strong>Via CLI<\/strong><\/em><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose configure\n\n<span class=\"c\"># Select \"Add Extension\"<\/span>\n<span class=\"c\"># Choose \"Command-line Extension\"<\/span>\n<span class=\"c\"># Enter details:<\/span>\nName: PostgreSQL Explorer\nCommand: uv run \/full\/path\/to\/mcp-postgres\/.venv\/bin\/mcp-postgres\nTimeout: 300\nEnvironment variables:\n  - DATABASE_URL: postgresql:\/\/user:pass@localhost\/mydb\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><em><strong>Via config.yaml<\/strong><\/em><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">extensions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">postgres<\/span><span class=\"pi\">:<\/span>\n    <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">stdio<\/span>\n    <span class=\"na\">command<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">uv\"<\/span>\n    <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s2\">\"<\/span><span class=\"s\">run\"<\/span><span class=\"pi\">,<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">\/Users\/dev\/mcp-postgres\/.venv\/bin\/mcp-postgres\"<\/span><span class=\"pi\">]<\/span>\n    <span class=\"na\">env<\/span><span class=\"pi\">:<\/span>\n      <span class=\"na\">DATABASE_URL<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">${DATABASE_URL}\"<\/span>\n    <span class=\"na\">timeout<\/span><span class=\"pi\">:<\/span> <span class=\"m\">300<\/span>\n    <span class=\"na\">enabled<\/span><span class=\"pi\">:<\/span> <span class=\"kc\">true<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong><em>Via Desktop UI<\/em><\/strong><\/p>\n\n<ol>\n<li>Open goose Desktop<\/li>\n<li>Click sidebar \u2192 Extensions<\/li>\n<li>Click \"Add custom extension\"<\/li>\n<li>\n<p>Fill in:<\/p>\n\n<ul>\n<li>Name: PostgreSQL Explorer<\/li>\n<li>Type: STDIO<\/li>\n<li>Command: <code>uv run \/full\/path\/to\/mcp-postgres\/.venv\/bin\/mcp-postgres<\/code>\n<\/li>\n<li>Environment: <code>DATABASE_URL=postgresql:\/\/...<\/code>\n<\/li>\n<li>Timeout: 300<\/li>\n<\/ul>\n<\/li>\n<li><p>Toggle ON<\/p><\/li>\n<\/ol>\n\n<p><strong>Step 6: Use the Extension<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>You: goose, what tools do you have?\n\nGoose: I have access to these PostgreSQL tools:\n       - list_tables: List all tables in a schema\n       - describe_table: Get detailed table schema\n       - execute_query: Run SELECT queries\n\nYou: List all tables in our database\n\nGoose: [Calls list_tables()]\n       I found these tables:\n       - users: User accounts and profiles\n       - posts: Blog posts and articles\n       - comments: User comments on posts\n       - tags: Content tags\n\nYou: Describe the users table\n\nGoose: [Calls describe_table(\"users\")]\n       The users table has the following structure:\n\n       Columns:\n       - id (uuid, primary key)\n       - email (varchar(255), not null, unique)\n       - username (varchar(50), not null)\n       - created_at (timestamp, default now())\n       - last_login (timestamp, nullable)\n\n       Indexes:\n       - users_pkey: PRIMARY KEY (id)\n       - users_email_idx: UNIQUE (email)\n       - users_username_idx: INDEX (username)\n\nYou: Show me the 5 most recent users\n\nGoose: [Calls execute_query(\"SELECT * FROM users ORDER BY created_at DESC\")]\n       Here are the 5 most recent users:\n\n       1. john_doe (john@example.com) - Joined 2 hours ago\n       2. jane_smith (jane@example.com) - Joined 5 hours ago\n       ...\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Advanced Extension Patterns\n<\/h4>\n\n<p><strong>1. Stateful Extensions<\/strong><br>\nSome extensions need to maintain state across requests:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">StatefulMCPServer<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">__init__<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">session_data<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">cache<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n\n    <span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">start_session<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">user_id<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n        <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Initialize user session<\/span><span class=\"sh\">\"\"\"<\/span>\n        <span class=\"n\">session_id<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">uuid<\/span><span class=\"p\">.<\/span><span class=\"nf\">uuid4<\/span><span class=\"p\">())<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">session_data<\/span><span class=\"p\">[<\/span><span class=\"n\">session_id<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">user_id<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">user_id<\/span><span class=\"p\">,<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">started_at<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">datetime<\/span><span class=\"p\">.<\/span><span class=\"nf\">now<\/span><span class=\"p\">(),<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">context<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{}<\/span>\n        <span class=\"p\">}<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">session_id<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">session_id<\/span><span class=\"p\">}<\/span>\n\n    <span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">update_context<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">session_id<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">key<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">:<\/span> <span class=\"n\">Any<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n        <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Update session context<\/span><span class=\"sh\">\"\"\"<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">session_id<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">session_data<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span><span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span><span class=\"n\">INVALID_PARAMS<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">Invalid session<\/span><span class=\"sh\">\"<\/span><span class=\"p\">))<\/span>\n\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">session_data<\/span><span class=\"p\">[<\/span><span class=\"n\">session_id<\/span><span class=\"p\">][<\/span><span class=\"sh\">\"<\/span><span class=\"s\">context<\/span><span class=\"sh\">\"<\/span><span class=\"p\">][<\/span><span class=\"n\">key<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">value<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">status<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">updated<\/span><span class=\"sh\">\"<\/span><span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>2. Streaming Responses<\/strong><br>\nFor long-running operations, stream results:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">analyze_codebase<\/span><span class=\"p\">(<\/span><span class=\"n\">directory<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">AsyncIterator<\/span><span class=\"p\">[<\/span><span class=\"nb\">str<\/span><span class=\"p\">]:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Analyze codebase with streaming progress updates<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">files<\/span> <span class=\"o\">=<\/span> <span class=\"n\">glob<\/span><span class=\"p\">.<\/span><span class=\"nf\">glob<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">directory<\/span><span class=\"si\">}<\/span><span class=\"s\">\/**\/*.py<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">recursive<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">yield<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Found <\/span><span class=\"si\">{<\/span><span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">files<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\"> Python files<\/span><span class=\"se\">\\n<\/span><span class=\"sh\">\"<\/span>\n\n    <span class=\"k\">for<\/span> <span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">file_path<\/span> <span class=\"ow\">in<\/span> <span class=\"nf\">enumerate<\/span><span class=\"p\">(<\/span><span class=\"n\">files<\/span><span class=\"p\">):<\/span>\n        <span class=\"c1\"># Analyze file\n<\/span>        <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nf\">analyze_file<\/span><span class=\"p\">(<\/span><span class=\"n\">file_path<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">yield<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">[<\/span><span class=\"si\">{<\/span><span class=\"n\">i<\/span><span class=\"o\">+<\/span><span class=\"mi\">1<\/span><span class=\"si\">}<\/span><span class=\"s\">\/<\/span><span class=\"si\">{<\/span><span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">files<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\">] <\/span><span class=\"si\">{<\/span><span class=\"n\">file_path<\/span><span class=\"si\">}<\/span><span class=\"s\">: <\/span><span class=\"si\">{<\/span><span class=\"n\">result<\/span><span class=\"si\">}<\/span><span class=\"se\">\\n<\/span><span class=\"sh\">\"<\/span>\n\n    <span class=\"k\">yield<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">Analysis complete<\/span><span class=\"se\">\\n<\/span><span class=\"sh\">\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>3. Resource Subscriptions<\/strong><br>\nEnable real-time updates for resources:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"nd\">@mcp.resource<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">file:\/\/\/{path}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">watch_file<\/span><span class=\"p\">(<\/span><span class=\"n\">path<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Resource that supports subscriptions<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">with<\/span> <span class=\"nf\">open<\/span><span class=\"p\">(<\/span><span class=\"n\">path<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">f<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">f<\/span><span class=\"p\">.<\/span><span class=\"nf\">read<\/span><span class=\"p\">()<\/span>\n\n<span class=\"c1\"># When file changes, send notification\n<\/span><span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">on_file_change<\/span><span class=\"p\">(<\/span><span class=\"n\">path<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">await<\/span> <span class=\"n\">mcp<\/span><span class=\"p\">.<\/span><span class=\"nf\">notify_resource_updated<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">file:\/\/\/<\/span><span class=\"si\">{<\/span><span class=\"n\">path<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>4. Error Handling Best Practices<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">mcp.types<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">ErrorData<\/span><span class=\"p\">,<\/span> <span class=\"n\">INTERNAL_ERROR<\/span><span class=\"p\">,<\/span> <span class=\"n\">INVALID_PARAMS<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">risky_operation<\/span><span class=\"p\">(<\/span><span class=\"n\">input_data<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Tool with comprehensive error handling<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"c1\"># Validate input\n<\/span>        <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">input_data<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span>\n                <span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span><span class=\"n\">INVALID_PARAMS<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">input_data cannot be empty<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">)<\/span>\n\n        <span class=\"c1\"># Perform operation\n<\/span>        <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">perform_operation<\/span><span class=\"p\">(<\/span><span class=\"n\">input_data<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">status<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">success<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">result<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">result<\/span><span class=\"p\">}<\/span>\n\n    <span class=\"k\">except<\/span> <span class=\"nb\">ValueError<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"c1\"># Input validation errors\n<\/span>        <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span>\n            <span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span><span class=\"n\">INVALID_PARAMS<\/span><span class=\"p\">,<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Invalid input: <\/span><span class=\"si\">{<\/span><span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span> <span class=\"k\">from<\/span> <span class=\"n\">e<\/span>\n\n    <span class=\"k\">except<\/span> <span class=\"nb\">ConnectionError<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"c1\"># Network\/connection errors\n<\/span>        <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span>\n            <span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span><span class=\"n\">INTERNAL_ERROR<\/span><span class=\"p\">,<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Connection failed: <\/span><span class=\"si\">{<\/span><span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span> <span class=\"k\">from<\/span> <span class=\"n\">e<\/span>\n\n    <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"c1\"># Unexpected errors\n<\/span>        <span class=\"k\">raise<\/span> <span class=\"n\">McpError<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">ErrorData<\/span><span class=\"p\">(<\/span><span class=\"n\">INTERNAL_ERROR<\/span><span class=\"p\">,<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Unexpected error\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>5. Authentication and Security<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">os<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">functools<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">wraps<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">require_auth<\/span><span class=\"p\">(<\/span><span class=\"n\">func<\/span><span class=\"p\">):<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Decorator to require authentication<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"nd\">@wraps<\/span><span class=\"p\">(<\/span><span class=\"n\">func<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">wrapper<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">,<\/span> <span class=\"o\">**<\/span><span class=\"n\">kwargs<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">api_key<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">API_KEY<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">api_key<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span>\n                <span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span><span class=\"n\">INVALID_PARAMS<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">API_KEY not configured<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nf\">func<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">,<\/span> <span class=\"o\">**<\/span><span class=\"n\">kwargs<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">wrapper<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"nd\">@require_auth<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">protected_operation<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Tool requiring authentication<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"c1\"># Verify API key with external service\n<\/span>    <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"nf\">verify_api_key<\/span><span class=\"p\">(<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">API_KEY<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)):<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span>\n            <span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span><span class=\"n\">INVALID_PARAMS<\/span><span class=\"p\">,<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">Invalid API key<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"nf\">perform_protected_operation<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>6. Rate Limiting<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">collections<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">defaultdict<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">datetime<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">datetime<\/span><span class=\"p\">,<\/span> <span class=\"n\">timedelta<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">RateLimiter<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">__init__<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">max_calls<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">window_seconds<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">max_calls<\/span> <span class=\"o\">=<\/span> <span class=\"n\">max_calls<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">window<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">timedelta<\/span><span class=\"p\">(<\/span><span class=\"n\">seconds<\/span><span class=\"o\">=<\/span><span class=\"n\">window_seconds<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">calls<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">defaultdict<\/span><span class=\"p\">(<\/span><span class=\"nb\">list<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">check_limit<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">identifier<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">now<\/span> <span class=\"o\">=<\/span> <span class=\"n\">datetime<\/span><span class=\"p\">.<\/span><span class=\"nf\">now<\/span><span class=\"p\">()<\/span>\n        <span class=\"c1\"># Remove old calls outside window\n<\/span>        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">calls<\/span><span class=\"p\">[<\/span><span class=\"n\">identifier<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n            <span class=\"n\">call_time<\/span> <span class=\"k\">for<\/span> <span class=\"n\">call_time<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">calls<\/span><span class=\"p\">[<\/span><span class=\"n\">identifier<\/span><span class=\"p\">]<\/span>\n            <span class=\"k\">if<\/span> <span class=\"n\">now<\/span> <span class=\"o\">-<\/span> <span class=\"n\">call_time<\/span> <span class=\"o\">&lt;<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">window<\/span>\n        <span class=\"p\">]<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">calls<\/span><span class=\"p\">[<\/span><span class=\"n\">identifier<\/span><span class=\"p\">])<\/span> <span class=\"o\">&gt;=<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">max_calls<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">False<\/span>\n\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">calls<\/span><span class=\"p\">[<\/span><span class=\"n\">identifier<\/span><span class=\"p\">].<\/span><span class=\"nf\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">now<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"bp\">True<\/span>\n\n<span class=\"n\">limiter<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">RateLimiter<\/span><span class=\"p\">(<\/span><span class=\"n\">max_calls<\/span><span class=\"o\">=<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"n\">window_seconds<\/span><span class=\"o\">=<\/span><span class=\"mi\">60<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">rate_limited_api_call<\/span><span class=\"p\">(<\/span><span class=\"n\">endpoint<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Tool with rate limiting<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">limiter<\/span><span class=\"p\">.<\/span><span class=\"nf\">check_limit<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">api_calls<\/span><span class=\"sh\">\"<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"nc\">McpError<\/span><span class=\"p\">(<\/span>\n            <span class=\"nc\">ErrorData<\/span><span class=\"p\">(<\/span>\n                <span class=\"n\">INTERNAL_ERROR<\/span><span class=\"p\">,<\/span>\n                <span class=\"sh\">\"<\/span><span class=\"s\">Rate limit exceeded. Try again in 60 seconds.<\/span><span class=\"sh\">\"<\/span>\n            <span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"nf\">call_external_api<\/span><span class=\"p\">(<\/span><span class=\"n\">endpoint<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Production Best Practices\n<\/h3>\n\n<h4>\n  \n  \n  1. Logging and Observability\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">logging<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">mcp.server.fastmcp<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">FastMCP<\/span>\n\n<span class=\"c1\"># Configure logging\n<\/span><span class=\"n\">logging<\/span><span class=\"p\">.<\/span><span class=\"nf\">basicConfig<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">level<\/span><span class=\"o\">=<\/span><span class=\"n\">logging<\/span><span class=\"p\">.<\/span><span class=\"n\">INFO<\/span><span class=\"p\">,<\/span>\n    <span class=\"nb\">format<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">%(asctime)s - %(name)s - %(levelname)s - %(message)s<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">handlers<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span>\n        <span class=\"n\">logging<\/span><span class=\"p\">.<\/span><span class=\"nc\">FileHandler<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">\/var\/log\/mcp-server.log<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n        <span class=\"n\">logging<\/span><span class=\"p\">.<\/span><span class=\"nc\">StreamHandler<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">]<\/span>\n<span class=\"p\">)<\/span>\n\n<span class=\"n\">logger<\/span> <span class=\"o\">=<\/span> <span class=\"n\">logging<\/span><span class=\"p\">.<\/span><span class=\"nf\">getLogger<\/span><span class=\"p\">(<\/span><span class=\"n\">__name__<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">mcp<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">FastMCP<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">my-server<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">monitored_operation<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Tool with comprehensive logging<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Operation started with data: <\/span><span class=\"si\">{<\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"si\">:<\/span><span class=\"mi\">50<\/span><span class=\"p\">]<\/span><span class=\"si\">}<\/span><span class=\"s\">...<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">perform_operation<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Operation completed successfully<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">result<\/span>\n    <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Operation failed: <\/span><span class=\"si\">{<\/span><span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">exc_info<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">raise<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  2. Configuration Management\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>from pydantic import BaseSettings, Field\nfrom typing import Optional\n\nclass ServerConfig(BaseSettings):\n    \"\"\"Configuration with validation\"\"\"\n    database_url: str = Field(..., env=\"DATABASE_URL\")\n    api_key: Optional[str] = Field(None, env=\"API_KEY\")\n    timeout: int = Field(300, env=\"TIMEOUT\")\n    max_connections: int = Field(10, env=\"MAX_CONNECTIONS\")\n    log_level: str = Field(\"INFO\", env=\"LOG_LEVEL\")\n\n    class Config:\n        env_file = \".env\"\n        env_file_encoding = \"utf-8\"\n\n# Load configuration\nconfig = ServerConfig()\n\n# Use in tools\n@mcp.tool()\ndef query_with_timeout(query: str) -&gt; Dict:\n    \"\"\"Query with configured timeout\"\"\"\n    conn = get_connection(\n        config.database_url,\n        timeout=config.timeout\n    )\n    # ... perform query\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  3. Testing Extensions\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># tests\/test_server.py\n<\/span><span class=\"kn\">import<\/span> <span class=\"n\">pytest<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">mcp_postgres.server<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">mcp<\/span>\n\n<span class=\"nd\">@pytest.mark.asyncio<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">test_list_tables<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Test list_tables tool<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"c1\"># Mock database connection\n<\/span>    <span class=\"k\">with<\/span> <span class=\"nf\">patch<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">mcp_postgres.server.get_connection<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">mock_conn<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">mock_cursor<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">MagicMock<\/span><span class=\"p\">()<\/span>\n        <span class=\"n\">mock_cursor<\/span><span class=\"p\">.<\/span><span class=\"n\">fetchall<\/span><span class=\"p\">.<\/span><span class=\"n\">return_value<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n            <span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">users<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">User accounts<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n            <span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">posts<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Blog posts<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">]<\/span>\n        <span class=\"n\">mock_conn<\/span><span class=\"p\">.<\/span><span class=\"n\">return_value<\/span><span class=\"p\">.<\/span><span class=\"n\">cursor<\/span><span class=\"p\">.<\/span><span class=\"n\">return_value<\/span><span class=\"p\">.<\/span><span class=\"n\">__enter__<\/span><span class=\"p\">.<\/span><span class=\"n\">return_value<\/span> <span class=\"o\">=<\/span> <span class=\"n\">mock_cursor<\/span>\n\n        <span class=\"c1\"># Call tool\n<\/span>        <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"n\">mcp<\/span><span class=\"p\">.<\/span><span class=\"nf\">call_tool<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">list_tables<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">schema<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">public<\/span><span class=\"sh\">'<\/span><span class=\"p\">})<\/span>\n\n        <span class=\"c1\"># Assert results\n<\/span>        <span class=\"k\">assert<\/span> <span class=\"nf\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">result<\/span><span class=\"p\">)<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span>\n        <span class=\"k\">assert<\/span> <span class=\"n\">result<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">][<\/span><span class=\"sh\">'<\/span><span class=\"s\">table_name<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">'<\/span><span class=\"s\">users<\/span><span class=\"sh\">'<\/span>\n\n<span class=\"nd\">@pytest.mark.asyncio<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">test_execute_query_validation<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Test query validation<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">with<\/span> <span class=\"n\">pytest<\/span><span class=\"p\">.<\/span><span class=\"nf\">raises<\/span><span class=\"p\">(<\/span><span class=\"n\">McpError<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">exc_info<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">await<\/span> <span class=\"n\">mcp<\/span><span class=\"p\">.<\/span><span class=\"nf\">call_tool<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">execute_query<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">query<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">DELETE FROM users<\/span><span class=\"sh\">'<\/span><span class=\"p\">})<\/span>\n\n    <span class=\"k\">assert<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">Only SELECT queries are allowed<\/span><span class=\"sh\">\"<\/span> <span class=\"ow\">in<\/span> <span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">exc_info<\/span><span class=\"p\">.<\/span><span class=\"n\">value<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nd\">@pytest.mark.asyncio<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">test_resource_access<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Test resource retrieval<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">with<\/span> <span class=\"nf\">patch<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">mcp_postgres.server.list_tables<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">mock_list<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">mock_list<\/span><span class=\"p\">.<\/span><span class=\"n\">return_value<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n            <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">table_name<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">users<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">description<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">User accounts<\/span><span class=\"sh\">'<\/span><span class=\"p\">}<\/span>\n        <span class=\"p\">]<\/span>\n\n        <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"n\">mcp<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_resource<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">postgres:\/\/schemas\/public\/tables<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">assert<\/span> <span class=\"sh\">'<\/span><span class=\"s\">users<\/span><span class=\"sh\">'<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">result<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  4. Performance Optimization\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">functools<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">lru_cache<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">asyncio<\/span>\n\n<span class=\"c1\"># Cache expensive operations\n<\/span><span class=\"nd\">@lru_cache<\/span><span class=\"p\">(<\/span><span class=\"n\">maxsize<\/span><span class=\"o\">=<\/span><span class=\"mi\">128<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">get_table_schema<\/span><span class=\"p\">(<\/span><span class=\"n\">table_name<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Cached schema retrieval<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nf\">fetch_schema_from_db<\/span><span class=\"p\">(<\/span><span class=\"n\">table_name<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># Batch operations\n<\/span><span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">batch_process<\/span><span class=\"p\">(<\/span><span class=\"n\">items<\/span><span class=\"p\">:<\/span> <span class=\"n\">List<\/span><span class=\"p\">[<\/span><span class=\"nb\">str<\/span><span class=\"p\">])<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">List<\/span><span class=\"p\">[<\/span><span class=\"n\">Dict<\/span><span class=\"p\">]:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Process items concurrently<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">tasks<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"nf\">process_item<\/span><span class=\"p\">(<\/span><span class=\"n\">item<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">item<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">items<\/span><span class=\"p\">]<\/span>\n    <span class=\"k\">return<\/span> <span class=\"k\">await<\/span> <span class=\"n\">asyncio<\/span><span class=\"p\">.<\/span><span class=\"nf\">gather<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">tasks<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># Connection pooling\n<\/span><span class=\"kn\">from<\/span> <span class=\"n\">psycopg2.pool<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">SimpleConnectionPool<\/span>\n\n<span class=\"n\">pool<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">SimpleConnectionPool<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">minconn<\/span><span class=\"o\">=<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">maxconn<\/span><span class=\"o\">=<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">dsn<\/span><span class=\"o\">=<\/span><span class=\"n\">config<\/span><span class=\"p\">.<\/span><span class=\"n\">database_url<\/span>\n<span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">get_pooled_connection<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Get connection from pool<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">pool<\/span><span class=\"p\">.<\/span><span class=\"nf\">getconn<\/span><span class=\"p\">()<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">return_connection<\/span><span class=\"p\">(<\/span><span class=\"n\">conn<\/span><span class=\"p\">):<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Return connection to pool<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">pool<\/span><span class=\"p\">.<\/span><span class=\"nf\">putconn<\/span><span class=\"p\">(<\/span><span class=\"n\">conn<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  5. Security Hardening\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">re<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">typing<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">List<\/span>\n\n<span class=\"c1\"># SQL injection prevention\n<\/span><span class=\"k\">def<\/span> <span class=\"nf\">sanitize_identifier<\/span><span class=\"p\">(<\/span><span class=\"n\">identifier<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Sanitize SQL identifiers<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">re<\/span><span class=\"p\">.<\/span><span class=\"nf\">match<\/span><span class=\"p\">(<\/span><span class=\"sa\">r<\/span><span class=\"sh\">'<\/span><span class=\"s\">^[a-zA-Z_][a-zA-Z0-9_]*, identifier):\n        raise ValueError(f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Invalid identifier: {identifier}<\/span><span class=\"sh\">\"<\/span><span class=\"s\">)\n    return identifier\n\n# Input validation\nfrom pydantic import BaseModel, validator\n\nclass QueryInput(BaseModel):\n    query: str\n    limit: int = 100\n\n    @validator(<\/span><span class=\"sh\">'<\/span><span class=\"n\">query<\/span><span class=\"sh\">'<\/span><span class=\"s\">)\n    def validate_query(cls, v):\n        if not v.strip().upper().startswith(<\/span><span class=\"sh\">'<\/span><span class=\"n\">SELECT<\/span><span class=\"sh\">'<\/span><span class=\"s\">):\n            raise ValueError(<\/span><span class=\"sh\">'<\/span><span class=\"n\">Only<\/span> <span class=\"n\">SELECT<\/span> <span class=\"n\">queries<\/span> <span class=\"n\">allowed<\/span><span class=\"sh\">'<\/span><span class=\"s\">)\n\n        # Block dangerous patterns\n        dangerous = [<\/span><span class=\"sh\">'<\/span><span class=\"n\">DROP<\/span><span class=\"sh\">'<\/span><span class=\"s\">, <\/span><span class=\"sh\">'<\/span><span class=\"n\">DELETE<\/span><span class=\"sh\">'<\/span><span class=\"s\">, <\/span><span class=\"sh\">'<\/span><span class=\"n\">UPDATE<\/span><span class=\"sh\">'<\/span><span class=\"s\">, <\/span><span class=\"sh\">'<\/span><span class=\"n\">INSERT<\/span><span class=\"sh\">'<\/span><span class=\"s\">, <\/span><span class=\"sh\">'<\/span><span class=\"n\">ALTER<\/span><span class=\"sh\">'<\/span><span class=\"s\">, <\/span><span class=\"sh\">'<\/span><span class=\"n\">CREATE<\/span><span class=\"sh\">'<\/span><span class=\"s\">]\n        if any(keyword in v.upper() for keyword in dangerous):\n            raise ValueError(<\/span><span class=\"sh\">'<\/span><span class=\"n\">Query<\/span> <span class=\"n\">contains<\/span> <span class=\"n\">forbidden<\/span> <span class=\"n\">keywords<\/span><span class=\"sh\">'<\/span><span class=\"s\">)\n\n        return v\n\n    @validator(<\/span><span class=\"sh\">'<\/span><span class=\"n\">limit<\/span><span class=\"sh\">'<\/span><span class=\"s\">)\n    def validate_limit(cls, v):\n        if v &lt; 1 or v &gt; 1000:\n            raise ValueError(<\/span><span class=\"sh\">'<\/span><span class=\"n\">Limit<\/span> <span class=\"n\">must<\/span> <span class=\"n\">be<\/span> <span class=\"n\">between<\/span> <span class=\"mi\">1<\/span> <span class=\"ow\">and<\/span> <span class=\"mi\">1000<\/span><span class=\"sh\">'<\/span><span class=\"s\">)\n        return v\n\n# Environment variable validation\ndef validate_environment():\n    <\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">Validate required environment variables<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n    required = [<\/span><span class=\"sh\">'<\/span><span class=\"n\">DATABASE_URL<\/span><span class=\"sh\">'<\/span><span class=\"s\">, <\/span><span class=\"sh\">'<\/span><span class=\"n\">API_KEY<\/span><span class=\"sh\">'<\/span><span class=\"s\">]\n    missing = [var for var in required if not os.getenv(var)]\n\n    if missing:\n        raise RuntimeError(f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Missing required environment variables: {missing}<\/span><span class=\"sh\">\"<\/span><span class=\"s\">)\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Publishing and Distribution\n<\/h3>\n\n<h4>\n  \n  \n  1. Publishing to PyPI\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Build package\n<\/span><span class=\"n\">uv<\/span> <span class=\"n\">build<\/span>\n\n<span class=\"c1\"># Upload to PyPI\n<\/span><span class=\"n\">uv<\/span> <span class=\"n\">publish<\/span> <span class=\"o\">--<\/span><span class=\"n\">token<\/span> <span class=\"err\">$<\/span><span class=\"n\">PYPI_TOKEN<\/span>\n\n<span class=\"c1\"># Install from PyPI\n<\/span><span class=\"n\">uvx<\/span> <span class=\"n\">mcp<\/span><span class=\"o\">-<\/span><span class=\"n\">postgres<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>pyproject.toml<\/code> <strong>for PyPI<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight toml\"><code><span class=\"nn\">[project]<\/span>\n<span class=\"py\">name<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"mcp-postgres\"<\/span>\n<span class=\"py\">version<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"0.1.0\"<\/span>\n<span class=\"py\">description<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"PostgreSQL explorer MCP server\"<\/span>\n<span class=\"py\">readme<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"README.md\"<\/span>\n<span class=\"py\">requires-python<\/span> <span class=\"p\">=<\/span> <span class=\"py\">\"&gt;<\/span><span class=\"p\">=<\/span><span class=\"mf\">3.10<\/span><span class=\"s\">\"<\/span><span class=\"err\">\n<\/span><span class=\"py\">license<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"py\">text<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"MIT\"<\/span><span class=\"p\">}<\/span>\n<span class=\"py\">authors<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"py\">{name<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"Your Name\"<\/span><span class=\"p\">,<\/span> <span class=\"py\">email<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"you@example.com\"<\/span><span class=\"err\">}<\/span>\n<span class=\"p\">]<\/span>\n<span class=\"py\">keywords<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span><span class=\"s\">\"mcp\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"postgresql\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"database\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"goose\"<\/span><span class=\"p\">]<\/span>\n<span class=\"py\">classifiers<\/span> <span class=\"p\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"s\">\"Development Status :: 4 - Beta\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"s\">\"Intended Audience :: Developers\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"s\">\"License :: OSI Approved :: MIT License\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"s\">\"Programming Language :: Python :: 3.10\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"s\">\"Programming Language :: Python :: 3.11\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"s\">\"Programming Language :: Python :: 3.12\"<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">]<\/span>\n\n<span class=\"nn\">[project.urls]<\/span>\n<span class=\"py\">Homepage<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"https:\/\/github.com\/username\/mcp-postgres\"<\/span>\n<span class=\"py\">Documentation<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"https:\/\/github.com\/username\/mcp-postgres#readme\"<\/span>\n<span class=\"py\">Repository<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"https:\/\/github.com\/username\/mcp-postgres\"<\/span>\n<span class=\"py\">Issues<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"https:\/\/github.com\/username\/mcp-postgres\/issues\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  2. Creating Installation Links\n<\/h4>\n\n<p>Generate deep links for easy installation<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">urllib.parse<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">urlencode<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">generate_goose_link<\/span><span class=\"p\">(<\/span><span class=\"n\">extension_config<\/span><span class=\"p\">:<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Generate Goose installation link<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">params<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">cmd<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">extension_config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">command<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">extension_config<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"mi\">300<\/span><span class=\"p\">),<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">extension_config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">id<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">name<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">extension_config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">name<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">description<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">extension_config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">description<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\"># Add args\n<\/span>    <span class=\"k\">for<\/span> <span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">arg<\/span> <span class=\"ow\">in<\/span> <span class=\"nf\">enumerate<\/span><span class=\"p\">(<\/span><span class=\"n\">extension_config<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">args<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">[])):<\/span>\n        <span class=\"n\">params<\/span><span class=\"p\">[<\/span><span class=\"sa\">f<\/span><span class=\"sh\">'<\/span><span class=\"s\">arg<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">arg<\/span>\n\n    <span class=\"c1\"># Add env vars\n<\/span>    <span class=\"k\">for<\/span> <span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">extension_config<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">env<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">{}).<\/span><span class=\"nf\">items<\/span><span class=\"p\">():<\/span>\n        <span class=\"n\">params<\/span><span class=\"p\">[<\/span><span class=\"sa\">f<\/span><span class=\"sh\">'<\/span><span class=\"s\">env.<\/span><span class=\"si\">{<\/span><span class=\"n\">key<\/span><span class=\"si\">}<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">value<\/span>\n\n    <span class=\"n\">base_url<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">goose:\/\/extension<\/span><span class=\"sh\">\"<\/span>\n    <span class=\"k\">return<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">base_url<\/span><span class=\"si\">}<\/span><span class=\"s\">?<\/span><span class=\"si\">{<\/span><span class=\"nf\">urlencode<\/span><span class=\"p\">(<\/span><span class=\"n\">params<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span>\n\n<span class=\"c1\"># Example usage\n<\/span><span class=\"n\">config<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">command<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">uvx<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">args<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">mcp-postgres<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">timeout<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"mi\">300<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">id<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">postgres<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">name<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">PostgreSQL Explorer<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">description<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Explore PostgreSQL databases<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"sh\">'<\/span><span class=\"s\">env<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">'<\/span><span class=\"s\">DATABASE_URL<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">${DATABASE_URL}<\/span><span class=\"sh\">'<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"n\">link<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">generate_goose_link<\/span><span class=\"p\">(<\/span><span class=\"n\">config<\/span><span class=\"p\">)<\/span>\n<span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Install link: <\/span><span class=\"si\">{<\/span><span class=\"n\">link<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  3. Documentation\n<\/h4>\n\n<p>Create comprehensive documentation<br>\n<code>README.md<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code># MCP PostgreSQL Explorer\n\nPostgreSQL database explorer for Goose via Model Context Protocol.\n\n## Features\n\n- \ud83d\udccb List all tables in a schema\n- \ud83d\udd0d Detailed table schema inspection\n- \ud83d\udd0e Execute SELECT queries safely\n- \ud83d\udcca Resource endpoints for real-time data\n- \ud83c\udfaf Optimized query prompts\n\n## Installation\n\n### Via uvx (Recommended)\n<\/code><\/pre>\n\n<\/div>\n\n<p><br>\nbash<br>\nuvx mcp-postgres<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\n### Via pip\n<\/code><\/pre>\n\n<\/div>\n\n<p><br>\nbash<br>\npip install mcp-postgres<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\n### Via Goose\n\nClick this link to install in Goose:\n\n[Install PostgreSQL Explorer](goose:\/\/extension?cmd=uvx&amp;arg=mcp-postgres&amp;...)\n\nOr manually:\n<\/code><\/pre>\n\n<\/div>\n\n<p><br>\nbash<br>\ngoose configure<\/p>\n<h1>\n  \n  \n  Select \"Add Extension\"\n<\/h1>\n<h1>\n  \n  \n  Command: uvx mcp-postgres\n<\/h1>\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\n## Configuration\n\nSet the `DATABASE_URL` environment variable:\n<\/code><\/pre>\n\n<\/div>\n<p><br>\nbash<br>\nexport DATABASE_URL=\"postgresql:\/\/user:password@localhost:5432\/mydb\"<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\nOr in Goose config:\n<\/code><\/pre>\n\n<\/div>\n\n<p><br>\nyaml<br>\nextensions:<br>\n  postgres:<br>\n    type: stdio<br>\n    command: \"uvx\"<br>\n    args: [\"mcp-postgres\"]<br>\n    env:<br>\n      DATABASE_URL: \"${DATABASE_URL}\"<br>\n    timeout: 300<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\n## Usage\n\nOnce installed, you can ask Goose:\n\n- \"List all tables in the database\"\n- \"Describe the users table\"\n- \"Show me the 10 most recent orders\"\n- \"What's the schema of the products table?\"\n\n## Tools\n\n### list_tables\n\nList all tables in a schema.\n\n**Parameters:**\n- `schema` (optional): Schema name (default: \"public\")\n\n**Returns:** List of tables with descriptions\n\n### describe_table\n\nGet detailed schema information.\n\n**Parameters:**\n- `table_name`: Name of the table\n- `schema` (optional): Schema name (default: \"public\")\n\n**Returns:** Complete table schema\n\n### execute_query\n\nExecute SELECT queries safely.\n\n**Parameters:**\n- `query`: SQL SELECT statement\n- `limit` (optional): Max rows (default: 100)\n\n**Returns:** Query results\n\n## Resources\n\n- `postgres:\/\/schemas\/{schema}\/tables` - List of tables in schema\n\n## Security\n\n- Only SELECT queries allowed\n- SQL injection prevention\n- Connection pooling\n- Rate limiting\n\n## Development\n<\/code><\/pre>\n\n<\/div>\n\n<p><br>\nbash<\/p>\n<h1>\n  \n  \n  Clone repository\n<\/h1>\n\n<p>git clone <a href=\"https:\/\/github.com\/username\/mcp-postgres\" rel=\"noopener noreferrer\">https:\/\/github.com\/username\/mcp-postgres<\/a><br>\ncd mcp-postgres<\/p>\n<h1>\n  \n  \n  Install dependencies\n<\/h1>\n\n<p>uv sync<\/p>\n<h1>\n  \n  \n  Run tests\n<\/h1>\n\n<p>uv run pytest<\/p>\n<h1>\n  \n  \n  Run in dev mode\n<\/h1>\n\n<p>mcp dev src\/mcp_postgres\/server.py<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\n## License\n\nMIT License - see LICENSE file\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Advanced Topics\n<\/h2>\n\n<h3>\n  \n  \n  1. Multi-Protocol Support\n<\/h3>\n\n<p>Supporting both STDIO and SSE<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">sys<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">asyncio<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">mcp.server.fastmcp<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">FastMCP<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">mcp.server.sse<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">SseServerTransport<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">mcp.server.stdio<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">StdioServerTransport<\/span>\n\n<span class=\"n\">mcp<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">FastMCP<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">multi-protocol-server<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># ... define tools, resources, prompts ...\n<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">main<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Run server with appropriate transport<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">if<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">--sse<\/span><span class=\"sh\">\"<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">sys<\/span><span class=\"p\">.<\/span><span class=\"n\">argv<\/span><span class=\"p\">:<\/span>\n        <span class=\"c1\"># Run as SSE server\n<\/span>        <span class=\"n\">transport<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">SseServerTransport<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\/sse<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">await<\/span> <span class=\"n\">mcp<\/span><span class=\"p\">.<\/span><span class=\"nf\">run<\/span><span class=\"p\">(<\/span><span class=\"n\">transport<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n        <span class=\"c1\"># Run as STDIO server\n<\/span>        <span class=\"n\">transport<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">StdioServerTransport<\/span><span class=\"p\">()<\/span>\n        <span class=\"k\">await<\/span> <span class=\"n\">mcp<\/span><span class=\"p\">.<\/span><span class=\"nf\">run<\/span><span class=\"p\">(<\/span><span class=\"n\">transport<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"n\">__name__<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">__main__<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">asyncio<\/span><span class=\"p\">.<\/span><span class=\"nf\">run<\/span><span class=\"p\">(<\/span><span class=\"nf\">main<\/span><span class=\"p\">())<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  2. Dynamic Tool Generation\n<\/h3>\n\n<p>Generate tools dynamically based on configuration<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">typing<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">List<\/span><span class=\"p\">,<\/span> <span class=\"n\">Dict<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">yaml<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">generate_tools_from_config<\/span><span class=\"p\">(<\/span><span class=\"n\">config_path<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">):<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Generate MCP tools from configuration file<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">with<\/span> <span class=\"nf\">open<\/span><span class=\"p\">(<\/span><span class=\"n\">config_path<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">f<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">config<\/span> <span class=\"o\">=<\/span> <span class=\"n\">yaml<\/span><span class=\"p\">.<\/span><span class=\"nf\">safe_load<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">for<\/span> <span class=\"n\">endpoint<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">endpoints<\/span><span class=\"sh\">'<\/span><span class=\"p\">]:<\/span>\n        <span class=\"k\">def<\/span> <span class=\"nf\">create_tool<\/span><span class=\"p\">(<\/span><span class=\"n\">endpoint_config<\/span><span class=\"p\">):<\/span>\n            <span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n            <span class=\"k\">def<\/span> <span class=\"nf\">dynamic_tool<\/span><span class=\"p\">(<\/span><span class=\"o\">**<\/span><span class=\"n\">kwargs<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n                <span class=\"sa\">f<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n                <\/span><span class=\"si\">{<\/span><span class=\"n\">endpoint_config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">description<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span><span class=\"si\">}<\/span><span class=\"s\">\n                <\/span><span class=\"sh\">\"\"\"<\/span>\n                <span class=\"k\">return<\/span> <span class=\"nf\">call_api<\/span><span class=\"p\">(<\/span>\n                    <span class=\"n\">endpoint_config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">url<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n                    <span class=\"n\">method<\/span><span class=\"o\">=<\/span><span class=\"n\">endpoint_config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">method<\/span><span class=\"sh\">'<\/span><span class=\"p\">],<\/span>\n                    <span class=\"n\">params<\/span><span class=\"o\">=<\/span><span class=\"n\">kwargs<\/span>\n                <span class=\"p\">)<\/span>\n\n            <span class=\"n\">dynamic_tool<\/span><span class=\"p\">.<\/span><span class=\"n\">__name__<\/span> <span class=\"o\">=<\/span> <span class=\"n\">endpoint_config<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">name<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">dynamic_tool<\/span>\n\n        <span class=\"nf\">create_tool<\/span><span class=\"p\">(<\/span><span class=\"n\">endpoint<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># Load tools from config\n<\/span><span class=\"nf\">generate_tools_from_config<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">tools_config.yaml<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>tools_config.yaml<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">endpoints<\/span><span class=\"pi\">:<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">get_user<\/span>\n    <span class=\"na\">description<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">Retrieve<\/span><span class=\"nv\"> <\/span><span class=\"s\">user<\/span><span class=\"nv\"> <\/span><span class=\"s\">information\"<\/span>\n    <span class=\"na\">url<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">https:\/\/api.example.com\/users\/{user_id}\"<\/span>\n    <span class=\"na\">method<\/span><span class=\"pi\">:<\/span> <span class=\"s\">GET<\/span>\n    <span class=\"na\">parameters<\/span><span class=\"pi\">:<\/span>\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">user_id<\/span>\n        <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">string<\/span>\n        <span class=\"na\">required<\/span><span class=\"pi\">:<\/span> <span class=\"kc\">true<\/span>\n\n  <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">create_user<\/span>\n    <span class=\"na\">description<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">Create<\/span><span class=\"nv\"> <\/span><span class=\"s\">new<\/span><span class=\"nv\"> <\/span><span class=\"s\">user\"<\/span>\n    <span class=\"na\">url<\/span><span class=\"pi\">:<\/span> <span class=\"s2\">\"<\/span><span class=\"s\">https:\/\/api.example.com\/users\"<\/span>\n    <span class=\"na\">method<\/span><span class=\"pi\">:<\/span> <span class=\"s\">POST<\/span>\n    <span class=\"na\">parameters<\/span><span class=\"pi\">:<\/span>\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">email<\/span>\n        <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">string<\/span>\n        <span class=\"na\">required<\/span><span class=\"pi\">:<\/span> <span class=\"kc\">true<\/span>\n      <span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">name<\/span>\n        <span class=\"na\">type<\/span><span class=\"pi\">:<\/span> <span class=\"s\">string<\/span>\n        <span class=\"na\">required<\/span><span class=\"pi\">:<\/span> <span class=\"kc\">true<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  3. Composite Extensions\n<\/h3>\n\n<p>Combine multiple data sources in one extension<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>class CompositeExtension:\n    def __init__(self):\n        self.postgres_client = PostgresClient()\n        self.redis_client = RedisClient()\n        self.elasticsearch_client = ESClient()\n\n    @mcp.tool()\n    def full_text_search(self, query: str) -&gt; Dict:\n        \"\"\"Search across multiple data sources\"\"\"\n        # Search Elasticsearch\n        es_results = self.elasticsearch_client.search(query)\n\n        # Enrich with database data\n        enriched = []\n        for result in es_results:\n            db_data = self.postgres_client.get_record(result['id'])\n            cache_data = self.redis_client.get(f\"meta:{result['id']}\")\n\n            enriched.append({\n                **result,\n                'details': db_data,\n                'cached_meta': cache_data\n            })\n\n        return {'results': enriched, 'total': len(enriched)}\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  4. Webhook Integration\n<\/h3>\n\n<p>Support real-time updates via webhooks<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">fastapi<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">FastAPI<\/span><span class=\"p\">,<\/span> <span class=\"n\">Request<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">threading<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Thread<\/span>\n\n<span class=\"n\">app<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">FastAPI<\/span><span class=\"p\">()<\/span>\n<span class=\"n\">mcp<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">FastMCP<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">webhook-server<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nd\">@app.post<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">\/webhook\/{resource_id}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">handle_webhook<\/span><span class=\"p\">(<\/span><span class=\"n\">resource_id<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">request<\/span><span class=\"p\">:<\/span> <span class=\"n\">Request<\/span><span class=\"p\">):<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Receive webhook and notify clients<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"nf\">json<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"c1\"># Update internal state\n<\/span>    <span class=\"nf\">update_resource<\/span><span class=\"p\">(<\/span><span class=\"n\">resource_id<\/span><span class=\"p\">,<\/span> <span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\"># Notify MCP clients of resource update\n<\/span>    <span class=\"k\">await<\/span> <span class=\"n\">mcp<\/span><span class=\"p\">.<\/span><span class=\"nf\">notify_resource_updated<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">webhook:\/\/<\/span><span class=\"si\">{<\/span><span class=\"n\">resource_id<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"p\">{<\/span><span class=\"sh\">\"<\/span><span class=\"s\">status<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">received<\/span><span class=\"sh\">\"<\/span><span class=\"p\">}<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">run_webhook_server<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Run webhook server in background<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"kn\">import<\/span> <span class=\"n\">uvicorn<\/span>\n    <span class=\"n\">uvicorn<\/span><span class=\"p\">.<\/span><span class=\"nf\">run<\/span><span class=\"p\">(<\/span><span class=\"n\">app<\/span><span class=\"p\">,<\/span> <span class=\"n\">host<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">0.0.0.0<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">port<\/span><span class=\"o\">=<\/span><span class=\"mi\">8000<\/span><span class=\"p\">)<\/span>\n\n<span class=\"c1\"># Start webhook server in separate thread\n<\/span><span class=\"n\">thread<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Thread<\/span><span class=\"p\">(<\/span><span class=\"n\">target<\/span><span class=\"o\">=<\/span><span class=\"n\">run_webhook_server<\/span><span class=\"p\">,<\/span> <span class=\"n\">daemon<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">thread<\/span><span class=\"p\">.<\/span><span class=\"nf\">start<\/span><span class=\"p\">()<\/span>\n\n<span class=\"c1\"># Run MCP server\n<\/span><span class=\"n\">mcp<\/span><span class=\"p\">.<\/span><span class=\"nf\">run<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Troubleshooting\n<\/h2>\n\n<h3>\n  \n  \n  Common Issues and Solutions\n<\/h3>\n\n<h4>\n  \n  \n  1. Connection Timeout\n<\/h4>\n\n<p><strong>Problem<\/strong>: Extension times out during initialization<br>\n<strong>Solutions<\/strong>:<\/p>\n\n<ul>\n<li>Increase timeout in config: <code>timeout: 600<\/code>\n<\/li>\n<li>Optimize initialization code<\/li>\n<li>Move expensive operations to lazy loading\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">LazyConnection<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">__init__<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">_conn<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">get_connection<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">_conn<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">_conn<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">create_connection<\/span><span class=\"p\">()<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">_conn<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  2. Environment Variables Not Loading\n<\/h4>\n\n<p><strong>Problem<\/strong>: Extension can't access environment variables<br>\n<strong>Solutions<\/strong>:<\/p>\n\n<ul>\n<li>Verify environment variables are set in goose config<\/li>\n<li>Use <code>${VAR_NAME}<\/code> syntax in config.yaml<\/li>\n<li>Check variable expansion: <code>echo $DATABASE_URL<\/code>\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"n\">extensions<\/span><span class=\"p\">:<\/span>\n  <span class=\"n\">myext<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">env<\/span><span class=\"p\">:<\/span>\n      <span class=\"n\">API_KEY<\/span><span class=\"p\">:<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">${MY_API_KEY}<\/span><span class=\"sh\">\"<\/span>  <span class=\"c1\"># Correct\n<\/span>      <span class=\"c1\"># API_KEY: \"$MY_API_KEY\"  # Wrong\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  3. Tool Not Appearing in Goose\n<\/h4>\n\n<p><strong>Problem<\/strong>: Defined tools don't show up<br>\n<strong>Solutions<\/strong>:<\/p>\n\n<ul>\n<li>Verify extension is enabled<\/li>\n<li>Check MCP Inspector shows tools<\/li>\n<li>Restart Goose after changes<\/li>\n<li>Check logs for errors\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Test with MCP Inspector<\/span>\nmcp dev src\/my_extension\/server.py\n\n<span class=\"c\"># Check Goose logs<\/span>\n<span class=\"nb\">tail<\/span> <span class=\"nt\">-f<\/span> ~\/.config\/goose\/logs\/goose.log\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  4. Permission Denied Errors\n<\/h4>\n\n<p><strong>Problem<\/strong>: Extension can't access resources<br>\n<strong>Solutions<\/strong>:<\/p>\n\n<ul>\n<li>Check file permissions<\/li>\n<li>Verify user has necessary access<\/li>\n<li>Use absolute paths<\/li>\n<li>Check SELinux\/AppArmor policies\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Fix permissions<\/span>\n<span class=\"nb\">chmod<\/span> +x .venv\/bin\/mcp-myext\n\n<span class=\"c\"># Check access<\/span>\n<span class=\"nb\">ls<\/span> <span class=\"nt\">-la<\/span> \/path\/to\/resource\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  5. Import Errors\n<\/h4>\n\n<p><strong>Problem<\/strong>: Python modules not found<br>\n<strong>Solutions<\/strong>:<\/p>\n\n<ul>\n<li>Install all dependencies: <code>uv sync<\/code>\n<\/li>\n<li>Verify virtual environment activation<\/li>\n<li>Check <code>pyproject.toml<\/code> dependencies<\/li>\n<li>Use absolute imports<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Performance Optimization\n<\/h3>\n\n<h4>\n  \n  \n  Benchmarking Extensions\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">time<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">functools<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">benchmark<\/span><span class=\"p\">(<\/span><span class=\"n\">func<\/span><span class=\"p\">):<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Decorator to measure tool execution time<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"nd\">@functools.wraps<\/span><span class=\"p\">(<\/span><span class=\"n\">func<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">wrapper<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">,<\/span> <span class=\"o\">**<\/span><span class=\"n\">kwargs<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">start<\/span> <span class=\"o\">=<\/span> <span class=\"n\">time<\/span><span class=\"p\">.<\/span><span class=\"nf\">perf_counter<\/span><span class=\"p\">()<\/span>\n        <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nf\">func<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">,<\/span> <span class=\"o\">**<\/span><span class=\"n\">kwargs<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">duration<\/span> <span class=\"o\">=<\/span> <span class=\"n\">time<\/span><span class=\"p\">.<\/span><span class=\"nf\">perf_counter<\/span><span class=\"p\">()<\/span> <span class=\"o\">-<\/span> <span class=\"n\">start<\/span>\n            <span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">info<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">func<\/span><span class=\"p\">.<\/span><span class=\"n\">__name__<\/span><span class=\"si\">}<\/span><span class=\"s\"> completed in <\/span><span class=\"si\">{<\/span><span class=\"n\">duration<\/span><span class=\"si\">:<\/span><span class=\"p\">.<\/span><span class=\"mi\">3<\/span><span class=\"n\">f<\/span><span class=\"si\">}<\/span><span class=\"s\">s<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">result<\/span>\n        <span class=\"k\">except<\/span> <span class=\"nb\">Exception<\/span> <span class=\"k\">as<\/span> <span class=\"n\">e<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">duration<\/span> <span class=\"o\">=<\/span> <span class=\"n\">time<\/span><span class=\"p\">.<\/span><span class=\"nf\">perf_counter<\/span><span class=\"p\">()<\/span> <span class=\"o\">-<\/span> <span class=\"n\">start<\/span>\n            <span class=\"n\">logger<\/span><span class=\"p\">.<\/span><span class=\"nf\">error<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">func<\/span><span class=\"p\">.<\/span><span class=\"n\">__name__<\/span><span class=\"si\">}<\/span><span class=\"s\"> failed after <\/span><span class=\"si\">{<\/span><span class=\"n\">duration<\/span><span class=\"si\">:<\/span><span class=\"p\">.<\/span><span class=\"mi\">3<\/span><span class=\"n\">f<\/span><span class=\"si\">}<\/span><span class=\"s\">s: <\/span><span class=\"si\">{<\/span><span class=\"n\">e<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">raise<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">wrapper<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"nd\">@benchmark<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">def<\/span> <span class=\"nf\">slow_operation<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Benchmarked tool<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"k\">return<\/span> <span class=\"k\">await<\/span> <span class=\"nf\">perform_operation<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Profiling\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">cProfile<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">pstats<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">profile_tool<\/span><span class=\"p\">():<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Profile tool performance<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">profiler<\/span> <span class=\"o\">=<\/span> <span class=\"n\">cProfile<\/span><span class=\"p\">.<\/span><span class=\"nc\">Profile<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">profiler<\/span><span class=\"p\">.<\/span><span class=\"nf\">enable<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"c1\"># Run operation\n<\/span>    <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">expensive_operation<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"n\">profiler<\/span><span class=\"p\">.<\/span><span class=\"nf\">disable<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">stats<\/span> <span class=\"o\">=<\/span> <span class=\"n\">pstats<\/span><span class=\"p\">.<\/span><span class=\"nc\">Stats<\/span><span class=\"p\">(<\/span><span class=\"n\">profiler<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">stats<\/span><span class=\"p\">.<\/span><span class=\"nf\">sort_stats<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">cumulative<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">stats<\/span><span class=\"p\">.<\/span><span class=\"nf\">print_stats<\/span><span class=\"p\">(<\/span><span class=\"mi\">20<\/span><span class=\"p\">)<\/span>  <span class=\"c1\"># Top 20 functions\n<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">result<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Real-World Extension Examples\n<\/h2>\n\n<h3>\n  \n  \n  1. GitHub Integration\n<\/h3>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">create_pull_request<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">repo<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">title<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">body<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">base<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">main<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">head<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">feature<\/span><span class=\"sh\">\"<\/span>\n<span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Create GitHub pull request<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">github<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Github<\/span><span class=\"p\">(<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">GITHUB_TOKEN<\/span><span class=\"sh\">\"<\/span><span class=\"p\">))<\/span>\n    <span class=\"n\">repository<\/span> <span class=\"o\">=<\/span> <span class=\"n\">github<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_repo<\/span><span class=\"p\">(<\/span><span class=\"n\">repo<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">pr<\/span> <span class=\"o\">=<\/span> <span class=\"n\">repository<\/span><span class=\"p\">.<\/span><span class=\"nf\">create_pull<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">title<\/span><span class=\"o\">=<\/span><span class=\"n\">title<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">body<\/span><span class=\"o\">=<\/span><span class=\"n\">body<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">base<\/span><span class=\"o\">=<\/span><span class=\"n\">base<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">head<\/span><span class=\"o\">=<\/span><span class=\"n\">head<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">number<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">pr<\/span><span class=\"p\">.<\/span><span class=\"n\">number<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">url<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">pr<\/span><span class=\"p\">.<\/span><span class=\"n\">html_url<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">state<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">pr<\/span><span class=\"p\">.<\/span><span class=\"n\">state<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"nd\">@mcp.resource<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">github:\/\/{owner}\/{repo}\/issues<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">get_issues<\/span><span class=\"p\">(<\/span><span class=\"n\">owner<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">repo<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Get repository issues as resource<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">github<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Github<\/span><span class=\"p\">(<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">GITHUB_TOKEN<\/span><span class=\"sh\">\"<\/span><span class=\"p\">))<\/span>\n    <span class=\"n\">repository<\/span> <span class=\"o\">=<\/span> <span class=\"n\">github<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_repo<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">owner<\/span><span class=\"si\">}<\/span><span class=\"s\">\/<\/span><span class=\"si\">{<\/span><span class=\"n\">repo<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">issues<\/span> <span class=\"o\">=<\/span> <span class=\"n\">repository<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_issues<\/span><span class=\"p\">(<\/span><span class=\"n\">state<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">open<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"sh\">\"<\/span><span class=\"se\">\\n<\/span><span class=\"sh\">\"<\/span><span class=\"p\">.<\/span><span class=\"nf\">join<\/span><span class=\"p\">([<\/span>\n        <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"s\">#<\/span><span class=\"si\">{<\/span><span class=\"n\">issue<\/span><span class=\"p\">.<\/span><span class=\"n\">number<\/span><span class=\"si\">}<\/span><span class=\"s\">: <\/span><span class=\"si\">{<\/span><span class=\"n\">issue<\/span><span class=\"p\">.<\/span><span class=\"n\">title<\/span><span class=\"si\">}<\/span><span class=\"s\"> (<\/span><span class=\"si\">{<\/span><span class=\"n\">issue<\/span><span class=\"p\">.<\/span><span class=\"n\">state<\/span><span class=\"si\">}<\/span><span class=\"s\">)<\/span><span class=\"sh\">\"<\/span>\n        <span class=\"k\">for<\/span> <span class=\"n\">issue<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">issues<\/span><span class=\"p\">[:<\/span><span class=\"mi\">50<\/span><span class=\"p\">]<\/span>\n    <span class=\"p\">])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  2. Slack Integration\n<\/h3>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">send_slack_message<\/span><span class=\"p\">(<\/span><span class=\"n\">channel<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">message<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Send message to Slack channel<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">client<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">WebClient<\/span><span class=\"p\">(<\/span><span class=\"n\">token<\/span><span class=\"o\">=<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">SLACK_TOKEN<\/span><span class=\"sh\">\"<\/span><span class=\"p\">))<\/span>\n\n    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">client<\/span><span class=\"p\">.<\/span><span class=\"nf\">chat_postMessage<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">channel<\/span><span class=\"o\">=<\/span><span class=\"n\">channel<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">text<\/span><span class=\"o\">=<\/span><span class=\"n\">message<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">ok<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">response<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">ok<\/span><span class=\"sh\">\"<\/span><span class=\"p\">],<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">ts<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">response<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">ts<\/span><span class=\"sh\">\"<\/span><span class=\"p\">],<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">channel<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">response<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">channel<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">search_slack_messages<\/span><span class=\"p\">(<\/span><span class=\"n\">query<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">count<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">20<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">List<\/span><span class=\"p\">[<\/span><span class=\"n\">Dict<\/span><span class=\"p\">]:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Search Slack messages<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">client<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">WebClient<\/span><span class=\"p\">(<\/span><span class=\"n\">token<\/span><span class=\"o\">=<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">SLACK_TOKEN<\/span><span class=\"sh\">\"<\/span><span class=\"p\">))<\/span>\n\n    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">client<\/span><span class=\"p\">.<\/span><span class=\"nf\">search_messages<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">query<\/span><span class=\"o\">=<\/span><span class=\"n\">query<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">count<\/span><span class=\"o\">=<\/span><span class=\"n\">count<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"p\">[<\/span>\n        <span class=\"p\">{<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">text<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">msg<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">text<\/span><span class=\"sh\">\"<\/span><span class=\"p\">],<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">user<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">msg<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">username<\/span><span class=\"sh\">\"<\/span><span class=\"p\">],<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">channel<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">msg<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">channel<\/span><span class=\"sh\">\"<\/span><span class=\"p\">][<\/span><span class=\"sh\">\"<\/span><span class=\"s\">name<\/span><span class=\"sh\">\"<\/span><span class=\"p\">],<\/span>\n            <span class=\"sh\">\"<\/span><span class=\"s\">timestamp<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">msg<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">ts<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span>\n        <span class=\"p\">}<\/span>\n        <span class=\"k\">for<\/span> <span class=\"n\">msg<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">response<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">messages<\/span><span class=\"sh\">\"<\/span><span class=\"p\">][<\/span><span class=\"sh\">\"<\/span><span class=\"s\">matches<\/span><span class=\"sh\">\"<\/span><span class=\"p\">]<\/span>\n    <span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  3. Jira Integration\n<\/h3>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"nd\">@mcp.tool<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">create_jira_ticket<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">project<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">summary<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">description<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">issue_type<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">\"<\/span><span class=\"s\">Task<\/span><span class=\"sh\">\"<\/span>\n<span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">:<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">Create Jira ticket<\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"n\">jira<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">JIRA<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">server<\/span><span class=\"o\">=<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">JIRA_URL<\/span><span class=\"sh\">\"<\/span><span class=\"p\">),<\/span>\n        <span class=\"n\">basic_auth<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">JIRA_EMAIL<\/span><span class=\"sh\">\"<\/span><span class=\"p\">),<\/span>\n            <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">\"<\/span><span class=\"s\">JIRA_API_TOKEN<\/span><span class=\"sh\">\"<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">)<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"n\">issue<\/span> <span class=\"o\">=<\/span> <span class=\"n\">jira<\/span><span class=\"p\">.<\/span><span class=\"nf\">create_issue<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">project<\/span><span class=\"o\">=<\/span><span class=\"n\">project<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">summary<\/span><span class=\"o\">=<\/span><span class=\"n\">summary<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">description<\/span><span class=\"o\">=<\/span><span class=\"n\">description<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">issuetype<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">name<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">issue_type<\/span><span class=\"p\">}<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">key<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"n\">issue<\/span><span class=\"p\">.<\/span><span class=\"n\">key<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">url<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">getenv<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">JIRA_URL<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\">\/browse\/<\/span><span class=\"si\">{<\/span><span class=\"n\">issue<\/span><span class=\"p\">.<\/span><span class=\"n\">key<\/span><span class=\"si\">}<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n        <span class=\"sh\">\"<\/span><span class=\"s\">status<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"nf\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">issue<\/span><span class=\"p\">.<\/span><span class=\"n\">fields<\/span><span class=\"p\">.<\/span><span class=\"n\">status<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Conclusion\n<\/h2>\n\n<p>The Model Context Protocol represents a paradigm shift in how AI systems integrate with external tools and data sources. By providing a standardized, secure, and extensible framework, MCP enables developers to build powerful integrations that extend Goose's capabilities far beyond its core functionality.<\/p>\n\n<h3>\n  \n  \n  Key Takeaways\n<\/h3>\n\n<ol>\n<li>\n<strong>MCP is Universal<\/strong>: Extensions built for Goose work with other MCP-compatible clients<\/li>\n<li>\n<strong>Three Primitives<\/strong>: Master prompts, resources, and tools to build comprehensive integrations<\/li>\n<li>\n<strong>Security First<\/strong>: Always validate inputs, handle errors gracefully, and protect sensitive data<\/li>\n<li>\n<strong>Test Thoroughly<\/strong>: Use MCP Inspector and unit tests to ensure reliability<\/li>\n<li>\n<strong>Document Well<\/strong>: Clear documentation ensures adoption and maintainability<\/li>\n<li>\n<strong>Think Composable<\/strong>: Build focused extensions that do one thing well<\/li>\n<\/ol>\n\n<h3>\n  \n  \n  Moving Forward\n<\/h3>\n\n<p><em>The MCP ecosystem is rapidly growing. As you build extensions:<\/em><\/p>\n\n<ul>\n<li>\n<strong>Share your wor<\/strong>k: Publish to PyPI and the MCP servers directory<\/li>\n<li>\n<strong>Contribute back<\/strong>: Help improve MCP SDKs and documentation<\/li>\n<li>\n<strong>Join the community<\/strong>: Connect with other developers building MCP servers<\/li>\n<li>\n<strong>Stay updated<\/strong>: MCP is evolving\u2014follow the specification for new features<\/li>\n<\/ul>\n\n<p><em>Whether you're building internal tools, integrating with third-party APIs, or creating entirely new workflows, MCP provides the foundation for robust, maintainable AI integrations.<br>\nNow go build something amazing!<\/em> <\/p>\n\n<h3>\n  \n  \n  Additional Resources\n<\/h3>\n\n<ul>\n<li><a href=\"https:\/\/spec.modelcontextprotocol.io\/\" rel=\"noopener noreferrer\">Official MCP Specification<\/a><\/li>\n<li>\n<a href=\"https:\/\/github.com\/modelcontextprotocol\/python-sdk\" rel=\"noopener noreferrer\">MCP Python SDK<\/a> <\/li>\n<li><a href=\"https:\/\/github.com\/modelcontextprotocol\/typescript-sdk\" rel=\"noopener noreferrer\">MCP TypeScript SDK<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/modelcontextprotocol\/servers\" rel=\"noopener noreferrer\">MCP Servers Directory<\/a><\/li>\n<li><a href=\"https:\/\/block.github.io\/goose\/docs\" rel=\"noopener noreferrer\">Goose Documentation<\/a><\/li>\n<li><a href=\"https:\/\/block.github.io\/goose\/docs\/tutorials\/custom-extensions\" rel=\"noopener noreferrer\">Goose Extensions Guide <\/a><\/li>\n<li><a href=\"https:\/\/discord.gg\/block-opensource\" rel=\"noopener noreferrer\">Community Discord<\/a><\/li>\n<\/ul>\n\n<p><em>Happy building! If you create an interesting MCP extension, share it with the <a href=\"https:\/\/discord.gg\/block-opensource\" rel=\"noopener noreferrer\">community<\/a>, we'd love to see what you build! \ud83e\udda2<\/em><\/p>\n\n","category":["goose","ai","mcp","opensource"]},{"title":"Best Practices for Prompt Engineering with goose","pubDate":"Wed, 15 Oct 2025 23:02:00 +0000","link":"https:\/\/dev.to\/lymah\/best-practices-for-prompt-engineering-with-goose-3m6h","guid":"https:\/\/dev.to\/lymah\/best-practices-for-prompt-engineering-with-goose-3m6h","description":"<h2>\n  \n  \n  Table of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>\nUnderstanding How goose Thinks\n\n<ul>\n<li>goose is Agentic, Not Just Conversational<\/li>\n<li>Context is Everything<\/li>\n<li>Different Models, Different Behaviors<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nCore Prompting Techniques for goose\n\n<ul>\n<li>1. Instruction-Based Prompting: The Foundation<\/li>\n<li>Chain-of-Thought Prompting: Breaking Down Complexity<\/li>\n<li>3. Few-Shot Prompting: Teaching by Example<\/li>\n<li>4. Iterative Refinement: The Conversation Loop<\/li>\n<li>5. Zero-Shot Prompting: Letting Goose Improvise<\/li>\n<li>6. Politeness-Based Prompting: Better Manners, Better Results<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nAdvanced Prompting Strategies\n\n<ul>\n<li>Setting Context and Preferences<\/li>\n<li>Task Decomposition<\/li>\n<li>Context Injection<\/li>\n<li>Constraint-Driven Prompting<\/li>\n<li>Comparative Analysis<\/li>\n<li>Error-Driven Development<\/li>\n<li>Documentation-First Approach<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nCommon Pitfalls and How to Avoid Them\n\n<ul>\n<li>Pitfall 1: Vague Instructions<\/li>\n<li>Pitfall 2: Assuming Goose Knows Your Codebase<\/li>\n<li>Pitfall 3: Not Providing Error Context<\/li>\n<li>Pitfall 4: Overloading a Single Prompt<\/li>\n<li>Pitfall 5: Ignoring Model Limitations<\/li>\n<li>Pitfall 6: Not Reviewing AI-Generated Code<\/li>\n<li>Pitfall 7: Forgetting to Specify Output Format<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nOptimizing for Different LLM Providers\n\n<ul>\n<li>GPT-4o (OpenAI)<\/li>\n<li>Claude (Anthropic)<\/li>\n<li>Gemini (Google)<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nBuilding Effective Workflows\n\n<ul>\n<li>The Debug Workflow<\/li>\n<li>The Feature Development Workflow<\/li>\n<li>The Learning Workflow<\/li>\n<li>The Code Review Workflow<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>Measuring Success: Prompt Quality Checklist<\/li>\n\n<li>Quick Reference: Prompt Templates<\/li>\n\n<li>\n\nBonus: Real-World Prompting Examples\n\n<ul>\n<li>Scenario 1: Debugging Production Issue<\/li>\n<li>Scenario 2: Implementing a New Feature<\/li>\n<li>Scenario 3: Code Quality Improvement<\/li>\n<li>Scenario 4: Performance Optimization<\/li>\n<li>Scenario 5: Security Audit<\/li>\n<li>Scenario 6: Documentation Generation<\/li>\n<li>Scenario 7: Test Coverage Improvement<\/li>\n<li>Scenario 8: Migration Planning<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nPro Tips from Experienced goose Users\n\n<ul>\n<li>Tip 1: Create Prompt Templates<\/li>\n<li>Tip 2: Use Session Context Strategically<\/li>\n<li>Tip 3: Leverage goose's Memory<\/li>\n<li>Tip 4: Progressive Disclosure<\/li>\n<li>Tip 5: Validate Before Accepting<\/li>\n<li>Tip 7: Context Files<\/li>\n<li>Tip 8: Error Log Analysis<\/li>\n<li>Tip 9: Comparative Learning<\/li>\n<li>Tip 10: Version-Specific Guidance<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nCommon goose Workflows\n\n<ul>\n<li>Morning Debug Ritual<\/li>\n<li>Code Review Workflow<\/li>\n<li>Learning New Technology<\/li>\n<li>Feature Development Sprint<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nTroubleshooting Your Prompts\n\n<ul>\n<li>If goose gives generic answers<\/li>\n<li>If Goose misunderstands<\/li>\n<li>If responses are too technical<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>Final Thoughts: Growing with goose<\/li>\n\n<li>\n\nConclusion\n\n<ul>\n<li>Key Takeaways<\/li>\n<li>Moving Forward<\/li>\n<li>Additional Resources<\/li>\n<li>Want to Learn More?<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Introduction\n<\/h2>\n\n<p>You've <a href=\"https:\/\/block.github.io\/goose\/docs\/getting-started\/installation\" rel=\"noopener noreferrer\">installed<\/a> goose, configured your LLM provider, and launched your first session. Now comes the real question: <em>how do you actually talk to an AI agent to get the results you want?<\/em><br>\nPrompt engineering, the art and science of communicating effectively with AI, is the difference between getting <strong>generic<\/strong>, <strong>unhelpful responses<\/strong> and <strong>having goose become your most productive coding partner<\/strong>. <em>Unlike simple chatbots, goose is an agentic AI that can execute commands, modify files, and orchestrate complex workflows. This makes effective prompting even more critical.<\/em><br>\nIn this comprehensive guide, we'll explore battle-tested strategies for crafting prompts that yield better results, avoid common pitfalls, and help you build a natural, productive workflow with goose. Whether you're debugging code, architecting new features, or refactoring legacy systems, these techniques will help you get the most out of your AI pair programmer.<\/p>\n<h2>\n  \n  \n  Understanding How goose Thinks\n<\/h2>\n\n<p>Before diving into specific techniques, it's important to understand what makes goose different from a standard chatbot.<\/p>\n<h3>\n  \n  \n  goose is Agentic, Not Just Conversational\n<\/h3>\n\n<p>Traditional AI assistants respond to your questions with text. goose can:<\/p>\n\n<ul>\n<li>Execute commands in your terminal<\/li>\n<li>Read and modify files in your project<\/li>\n<li>Install dependencies and manage packages<\/li>\n<li>Run tests and interpret results<\/li>\n<li>Make sequential decisions based on outcomes<\/li>\n<li>Access your project context, including file structure, git history, and more<\/li>\n<\/ul>\n\n<p>This means your prompts aren't just questions; they're instructions that trigger real actions in your development environment.<\/p>\n<h2>\n  \n  \n  Context is Everything\n<\/h2>\n\n<p>goose works best when given specific instructions with all important details included. The AI maintains conversation history and can reference previous exchanges, but it doesn't read your mind. The more context you provide upfront, the better goose can help.<\/p>\n<h2>\n  \n  \n  Different Models, Different Behaviors\n<\/h2>\n\n<p>Since goose supports multiple LLM providers (OpenAI, Claude, Gemini, etc.), the way it responds depends on which model you're using, with some LLMs needing extra guidance while others might require a few rounds of refinement. Understanding your model's strengths helps you adjust your prompting style accordingly.<\/p>\n<h2>\n  \n  \n  Core Prompting Techniques for goose\n<\/h2>\n\n<p>Let's explore the fundamental approaches to prompting, each suited to different scenarios.<\/p>\n<h3>\n  \n  \n  1. Instruction-Based Prompting: The Foundation\n<\/h3>\n\n<p>If you're new to goose, instruction-based prompting is a great place to start, where being clear and direct gets the best responses.<\/p>\n\n<p><strong>The Pattern<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, <span class=\"o\">[<\/span>action verb] <span class=\"o\">[<\/span>specific task] <span class=\"o\">[<\/span>with context\/constraints]\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>\u274c Weak Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, fix my code\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Problem<\/strong>: Too vague. Which code? What's broken? What's the expected behavior?<\/p>\n\n<p><strong>\u2705 Strong Prompt:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, the authentication <span class=\"k\">function in <\/span>src\/auth\/login.js is throwing a 401 error \neven with valid credentials. The issue started after I upgraded to Express 5. \nCan you debug this and fix the problem?\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong><em>Why it works<\/em><\/strong><\/p>\n\n<ul>\n<li>Specifies exact file location<\/li>\n<li>Describes the symptom clearly<\/li>\n<li>Provides context (Express 5 upgrade)<\/li>\n<li>States desired outcome<\/li>\n<\/ul>\n\n<p><strong>Real-World Examples<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>\u2705 <span class=\"s2\">\"goose, create a new React component called UserProfile that displays \n   user data from our API. It should include avatar, name, email, and bio. \n   Use TypeScript and follow our existing component patterns in src\/components\/\"<\/span>\n\n\u2705 <span class=\"s2\">\"goose, refactor the database queries in models\/user.js to use async\/await \n   instead of callbacks. Make sure to handle errors properly and maintain \n   backward compatibility with the existing API.\"<\/span>\n\n\u2705 <span class=\"s2\">\"goose, write unit tests for the PaymentProcessor class using Jest. \n   Cover success cases, validation errors, and network failures. Follow \n   the test structure we use in __tests__\/services\/\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Pro Tips<\/strong><\/p>\n\n<ul>\n<li>Use action verbs: create, refactor, debug, optimize, test, document<\/li>\n<li>Include file paths when relevant<\/li>\n<li>Mention coding standards or patterns to follow<\/li>\n<li>Specify constraints (performance, compatibility, style)<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Chain-of-Thought Prompting: Breaking Down Complexity\n<\/h3>\n\n<p>Chain-of-Thought Prompting helps when a topic or task is too much to tackle all at once, guiding goose to break things down step by step.<\/p>\n\n<p><strong>When to Use<\/strong><\/p>\n\n<ul>\n<li>Complex architectural decisions<\/li>\n<li>Multi-step migrations<\/li>\n<li>Learning unfamiliar concepts<\/li>\n<li>Planning before implementation<\/li>\n<\/ul>\n\n<p><strong>\u274c Overwhelming Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, migrate our app from MongoDB to PostgreSQL\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Structured Chain-of-Thought<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, I need to migrate our app from MongoDB to PostgreSQL. Let<span class=\"s1\">'s approach \nthis step by step:\n\n1. First, analyze our current MongoDB schema and data models\n2. Design an equivalent PostgreSQL schema\n3. Identify any breaking changes or data transformations needed\n4. Plan the migration strategy (downtime vs. gradual)\n5. Propose a testing approach\n\nLet'<\/span>s start with step 1. Can you analyze our models <span class=\"k\">in <\/span>src\/models\/ and \nsummarize the current schema structure?\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why it works<\/strong><\/p>\n\n<ul>\n<li>Breaks overwhelming task into manageable steps<\/li>\n<li>Allows you to validate each step before proceeding<\/li>\n<li>Gives goose clear direction at each stage<\/li>\n<li>Prevents premature optimization or rushed decisions<\/li>\n<\/ul>\n\n<p><strong>Example Conversation Flow<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>You: goose, walk me through implementing rate limiting <span class=\"k\">for <\/span>our API, \n     step by step\n\ngoose: I<span class=\"s1\">'ll break this down into steps:\n       1. Choose a rate limiting strategy (token bucket, sliding window, etc.)\n       2. Select a storage backend (Redis, in-memory, etc.)\n       3. Implement the middleware\n       4. Add rate limit headers\n       5. Configure per-endpoint limits\n       6. Add testing\n\n       Let'<\/span>s start with step 1. For your API, I recommend...\n\nYou: That makes sense. Let<span class=\"s1\">'s proceed with the token bucket strategy using \n     Redis. Show me step 2.\n\ngoose: For Redis storage, we'<\/span>ll need to...\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Pro Tips<\/strong><\/p>\n\n<ul>\n<li>Explicitly ask Goose to explain things \"step by step\"<\/li>\n<li>Validate each step before moving forward<\/li>\n<li>Use follow-up prompts: \"Now let's move to step 3\"<\/li>\n<li>Save complex chains as templates for future use<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  3. Few-Shot Prompting: Teaching by Example\n<\/h3>\n\n<p>Few-Shot Prompting works by showing goose examples of what you want, helping it match a specific style or format by providing references to skip the guesswork.<\/p>\n\n<p><strong>When to Use<\/strong><\/p>\n\n<ul>\n<li>Maintaining consistent code style<\/li>\n<li>Generating documentation in your format<\/li>\n<li>Following specific naming conventions<\/li>\n<li>Replicating existing patterns<\/li>\n<\/ul>\n\n<p><strong>\u274c Generic Reques<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, write API documentation <span class=\"k\">for <\/span>our endpoints\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>\u2705 Few-Shot with Examples<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, I need API documentation following our existing format. Here<span class=\"s1\">'s an example \nof how we document endpoints:\n\n\"\"\"\n## POST \/api\/users\/create\n\nCreates a new user account.\n\n**Request Body:**\n{\n  \"email\": \"string (required)\",\n  \"name\": \"string (required)\",\n  \"role\": \"enum ['<\/span>admin<span class=\"s1\">', '<\/span>user<span class=\"s1\">'] (optional, default: '<\/span>user<span class=\"s1\">')\"\n}\n\n**Success Response (201):**\n{\n  \"id\": \"uuid\",\n  \"email\": \"string\",\n  \"created_at\": \"timestamp\"\n}\n\n**Error Responses:**\n- 400: Invalid request body\n- 409: Email already exists\n\"\"\"\n\nNow document the following endpoints in the same format:\n- GET \/api\/users\/:id\n- PUT \/api\/users\/:id\n- DELETE \/api\/users\/:id\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why it works<\/strong><\/p>\n\n<ul>\n<li>Eliminates ambiguity about format<\/li>\n<li>Maintains consistency across documentation<\/li>\n<li>Reduces need for corrections<\/li>\n<li>Helps goose understand your team's conventions<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Practical Applications\n<\/h4>\n\n<p><strong>1. Code Style Consistency<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, our team uses this error handling pattern:\n\ntry <span class=\"o\">{<\/span>\n  const result <span class=\"o\">=<\/span> await someAsyncOperation<span class=\"o\">()<\/span><span class=\"p\">;<\/span>\n  <span class=\"k\">return<\/span> <span class=\"o\">{<\/span> success: <span class=\"nb\">true<\/span>, data: result <span class=\"o\">}<\/span><span class=\"p\">;<\/span>\n<span class=\"o\">}<\/span> catch <span class=\"o\">(<\/span>error<span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n  logger.error<span class=\"o\">(<\/span><span class=\"s1\">'Operation failed:'<\/span>, error<span class=\"o\">)<\/span><span class=\"p\">;<\/span>\n  <span class=\"k\">return<\/span> <span class=\"o\">{<\/span> success: <span class=\"nb\">false<\/span>, error: error.message <span class=\"o\">}<\/span><span class=\"p\">;<\/span>\n<span class=\"o\">}<\/span>\n\nApply this pattern to all async functions <span class=\"k\">in <\/span>src\/services\/payment.js\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>2. Commit Message Format<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, our commit messages follow this format:\n\nfeat<span class=\"o\">(<\/span>auth<span class=\"o\">)<\/span>: add OAuth2 support <span class=\"k\">for <\/span>Google login\n\n- Implement OAuth2 flow\n- Add Google provider configuration\n- Update user model to store OAuth tokens\n\nCloses <span class=\"c\">#123<\/span>\n\nWrite a commit message <span class=\"k\">for <\/span>the changes you just made.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Pro Tips<\/strong><\/p>\n\n<ul>\n<li>Always provide 1-3 examples for best results<\/li>\n<li>Show edge cases in your examples if relevant<\/li>\n<li>Include comments explaining non-obvious decisions<\/li>\n<li>Reference existing files: \"Follow the pattern in <code>src\/utils\/helpers.js<\/code>\"<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  4. Iterative Refinement: The Conversation Loop\n<\/h3>\n\n<p>Iterative Refinement Prompting acknowledges that AI agents aren't always going to get it right on the first try, allowing you to steer the conversation by giving feedback on what needs to change.<\/p>\n\n<p><strong>The Pattern<\/strong><br>\n<em>Initial prompt \u2192 Review output \u2192 Provide specific feedback \u2192 Repeat until satisfied<\/em><\/p>\n\n<p><strong>Example Refinement Flow<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>You: goose, create a <span class=\"k\">function <\/span>that validates email addresses\n\ngoose: <span class=\"o\">[<\/span>Generates basic regex validation]\n\nYou: This is too simple. Add validation <span class=\"k\">for<\/span>:\n     - Disposable email providers <span class=\"o\">(<\/span>block them<span class=\"o\">)<\/span>\n     - Common typos <span class=\"o\">(<\/span>gmail.con \u2192 gmail.com<span class=\"o\">)<\/span>\n     - International domains\n     Also add proper error messages <span class=\"k\">for <\/span>each validation failure\n\ngoose: <span class=\"o\">[<\/span>Generates improved version with additional checks]\n\nYou: Good! Now add unit tests covering all validation cases\n\ngoose: <span class=\"o\">[<\/span>Adds comprehensive tests]\n\nYou: Perfect. One more thing\u2014add TypeScript types and JSDoc comments\n\ngoose: <span class=\"o\">[<\/span>Final polished version]\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why This Works<\/strong><\/p>\n\n<ul>\n<li>You maintain control over the direction<\/li>\n<li>Avoids starting over when close to target<\/li>\n<li>Builds on previous work incrementally<\/li>\n<li>Teaches goose your preferences over time<\/li>\n<\/ul>\n\n<p><strong>Refinement Phrases That Work<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>- <span class=\"s2\">\"This is too technical. Simplify it for junior developers\"<\/span>\n- <span class=\"s2\">\"Add error handling for network failures\"<\/span>\n- <span class=\"s2\">\"This works but isn't performant. Optimize for large datasets\"<\/span>\n- <span class=\"s2\">\"Follow the existing code style in this project\"<\/span>\n- <span class=\"s2\">\"Add logging and monitoring hooks\"<\/span>\n- <span class=\"s2\">\"Make this more defensive\u2014validate all inputs\"<\/span>\n- <span class=\"s2\">\"Extract this into smaller, reusable functions\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Catching Hallucinations<\/strong><\/p>\n\n<p>When something sounds off, you can fact-check by asking \"where did you get that information? How do you know it's accurate?\"<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>You: goose, implement WebSocket authentication using JWT\n\ngoose: <span class=\"o\">[<\/span>Suggests using a library that doesn<span class=\"s1\">'t exist]\n\nYou: I can'<\/span>t find the library <span class=\"s1\">'ws-jwt-auth'<\/span> you mentioned. \n     Are you sure that exists? What<span class=\"s1\">'s the actual package name?\n\ngoose: You'<\/span>re right, I apologize. The actual approach is to...\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Pro Tips<\/strong><\/p>\n\n<ul>\n<li>Think of working with Goose like pair programming\u2014sometimes you need to clarify what you want or redirect the conversation<\/li>\n<li>Be specific in your feedback: \"too technical\" is better than just \"no\"<\/li>\n<li>Build incrementally rather than asking for everything at once<\/li>\n<li>Save successful refinement patterns for similar tasks<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  5. Zero-Shot Prompting: Letting Goose Improvise\n<\/h3>\n\n<p>Zero-Shot Prompting lets Goose figure things out on its own without examples or extra guidance, useful when you want creative ideas and have a rough direction but no clear plan.<\/p>\n\n<p><strong>When to Use<\/strong><\/p>\n\n<ul>\n<li>Brainstorming and exploration<\/li>\n<li>Open-ended problem solving<\/li>\n<li>Getting unstuck on design decisions<\/li>\n<li>Discovering alternatives you hadn't considered<\/li>\n<\/ul>\n\n<p><strong><em>Examples<\/em><\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>\u2705 <span class=\"s2\">\"goose, I need to build a real-time collaborative editor. \n    What's the best approach?\"<\/span>\n\n\u2705 <span class=\"s2\">\"goose, our API is slow. Analyze the code and suggest \n    performance optimizations\"<\/span>\n\n\u2705 <span class=\"s2\">\"goose, we need to add analytics tracking. What should \n    we track and how?\"<\/span>\n\n\u2705 <span class=\"s2\">\"goose, I'm stuck on this algorithm problem. Any creative \n    solutions?\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>The Power of Open-Ended Exploration<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>You: goose, I want to build a developer tool that makes code reviews \n     easier. Give me some ideas\n\ngoose: Here are several approaches you could take:\n\n1. <span class=\"k\">**<\/span>PR Checklist Automation<span class=\"k\">**<\/span>\n   - Auto-generate checklists based on changed files\n   - Integrate with GitHub\/GitLab APIs\n   - Track completion across team members\n\n2. <span class=\"k\">**<\/span>AI-Powered Code Analysis<span class=\"k\">**<\/span>\n   - Highlight potential bugs before human review\n   - Suggest <span class=\"nb\">test <\/span>cases <span class=\"k\">for <\/span>changed code\n   - Check <span class=\"k\">for <\/span>security vulnerabilities\n\n3. <span class=\"k\">**<\/span>Review Session Coordinator<span class=\"k\">**<\/span>\n   - Schedule real-time review sessions\n   - Screen sharing with code annotation\n   - Record decisions and action items\n\nWhich direction interests you most?\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why It Works<\/strong><\/p>\n\n<ul>\n<li>Original ideas often end up 10x better by letting goose take the lead and suggest things you might never have thought of<\/li>\n<li>Removes pressure of having everything figured out<\/li>\n<li>Surfaces options you might not know exist<\/li>\n<li>Can lead to innovative solutions<\/li>\n<\/ul>\n\n<p><strong>Pro Tips<\/strong><\/p>\n\n<ul>\n<li>Start broad, then narrow down based on responses<\/li>\n<li>Ask \"what else?\" to explore more options<\/li>\n<li>Follow up with \"why did you suggest that?\"<\/li>\n<li>Combine with iterative refinement once direction is clear<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  6. Politeness-Based Prompting: Better Manners, Better Results\n<\/h3>\n\n<p>Being polite actually makes AI responses better, as AI models tend to generate more thoughtful, structured, and friendlier replies when asked nicely.<\/p>\n\n<p><strong>The Science Behind It<\/strong><br>\nLLMs are trained on human text, including polite conversations that typically involve more care and detail. Saying \"please\" and \"thank you\" actually makes a difference in response quality.<\/p>\n\n<p><strong>\u274c Blunt Command<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, generate API documentation\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>\u2705 Polite Request<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, could you <span class=\"nb\">help <\/span>me generate comprehensive API documentation \n<span class=\"k\">for <\/span>our endpoints? I<span class=\"s1\">'d really appreciate it. Thanks!\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Real Impact<\/strong><br>\nThe responses to polite prompts tend to be:<\/p>\n\n<ul>\n<li>More thorough and detailed<\/li>\n<li>Better structured<\/li>\n<li>Include helpful explanations<\/li>\n<li>Sometimes even warmer in tone<\/li>\n<\/ul>\n\n<p><strong>Examples of Polite Prompting<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>\u2705 <span class=\"s2\">\"goose, I'd appreciate your help debugging this issue. Could you \n    take a look at the error logs? Thank you!\"<\/span>\n\n\u2705 <span class=\"s2\">\"goose, please review this code and let me know if you spot any \n    issues. I value your input!\"<\/span>\n\n\u2705 <span class=\"s2\">\"goose, thanks for that solution! Could we also add error handling? \n    I appreciate your help!\"<\/span>\n\n\u2705 <span class=\"s2\">\"goose, I'm grateful for your assistance on this project. One more \n    thing\u2014could you add some comments explaining the complex logic?\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Bonus: Goose Can Be Surprisingly Wholesome\n<\/h4>\n\n<p>One user received a sweet response from Goose at the end of a project, where it was genuinely grateful for the collaboration and even wished them sweet dreams. The relationship you build with your AI assistant matters!<\/p>\n\n<p><strong>Pro Tips<\/strong><\/p>\n\n<ul>\n<li>Add \"please\" and \"thank you\" naturally<\/li>\n<li>Express appreciation for good work: \"Great job on that!\"<\/li>\n<li>Use encouraging language: \"This is helpful, and...\"<\/li>\n<li>This works with any prompting style<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Advanced Prompting Strategies\n<\/h2>\n\n<p>Once you've mastered the basics, these advanced techniques will take your goose interactions to the next level.<\/p>\n\n<h3>\n  \n  \n  Setting Context and Preferences\n<\/h3>\n\n<p>If you're using the Memory Extension, you can train goose to remember your preferences across sessions.<\/p>\n\n<p><strong>Setting Global Preferences<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, remember these preferences:\n- I prefer functional programming style over OOP\n- Use TypeScript <span class=\"k\">for <\/span>all new JavaScript files\n- Follow Airbnb style guide <span class=\"k\">for <\/span>code formatting\n- Add comprehensive JSDoc comments\n- Write tests <span class=\"k\">in <\/span>Jest, not Mocha\n- I<span class=\"s1\">'m working on a Node.js backend with Express and PostgreSQL\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Role-Based Context<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose, remember: I<span class=\"s1\">'m a frontend developer learning backend development. \nWhen explaining backend concepts:\n- Compare them to frontend equivalents when possible\n- Explain why things work a certain way\n- Point out common pitfalls for frontend devs moving to backend\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Task Decomposition\n<\/h3>\n\n<p>For large, complex tasks, break them into manageable chunks.<\/p>\n\n<p><strong>Master Task with Sub-Prompts<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>You: goose, I need to implement user authentication. Let<span class=\"s1\">'s break this \n     into phases:\n\n     Phase 1: Database schema and models\n     Phase 2: Registration and login endpoints  \n     Phase 3: JWT token generation and validation\n     Phase 4: Password reset flow\n     Phase 5: Email verification\n\n     Let'<\/span>s start with Phase 1. Design the user table schema with \n     all necessary fields <span class=\"k\">for <\/span>authentication.\n\n<span class=\"o\">[<\/span>Complete Phase 1]\n\nYou: Great! Phase 1 complete. Now <span class=\"nb\">let<\/span><span class=\"s1\">'s move to Phase 2...\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Context Injection\n<\/h4>\n\n<p>Help goose understand your project better by providing relevant context upfront.<\/p>\n\n<p><strong>Project Structure Context<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, here's our project structure:\n\nsrc\/\n  controllers\/  - Request handlers\n  models\/       - Database models (Sequelize)\n  services\/     - Business logic\n  middleware\/   - Express middleware\n  utils\/        - Helper functions\n  routes\/       - API route definitions\n\nWe follow this pattern:\n- Routes call controllers\n- Controllers call services  \n- Services interact with models\n- All business logic stays in services\n\nNow, help me add a new feature: user profile updates\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Constraint-Driven Prompting\n<\/h3>\n\n<p>Specify constraints to get more targeted solutions<\/p>\n\n<p><strong>Performance Constraints<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, optimize this database query. Constraints:\n- Must handle 10,000+ records efficiently\n- Keep response time under 200ms\n- Minimize database round trips\n- Acceptable to cache results for 5 minutes\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Compatibility Constraints<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, refactor this code. Requirements:\n- Must work in Node.js 14+ (no newer syntax)\n- Cannot add new dependencies\n- Maintain backward compatibility with existing API\n- No breaking changes to function signatures\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Resource Constraints<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, implement image processing. Limits:\n- Max memory usage: 512MB\n- Process images up to 10MB\n- Must handle 100 concurrent requests\n- Optimize for serverless environment (cold starts matter)\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Comparative Analysis\n<\/h4>\n\n<p>Ask goose to compare approaches and recommend the best option.<br>\n<strong>Approach Comparison<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, I need to implement caching. Compare these approaches and \nrecommend the best one for our use case:\n\n1. Redis\n2. Memcached  \n3. In-memory (Node.js)\n4. HTTP cache headers\n\nOur requirements:\n- Distributed system (multiple servers)\n- TTL support\n- Cache invalidation on updates\n- Budget-conscious\n\nAnalyze pros, cons, and recommend with justification.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Error-Driven Development\n<\/h4>\n\n<p>Use errors as prompts for improvements.<\/p>\n\n<p><strong>Iterating on Failures<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>You: goose, run the test suite\n\ngoose: [Tests fail with specific errors]\n\nYou: Fix the failing tests. For each failure:\n     1. Explain why it's failing\n     2. Show the fix\n     3. Verify the fix resolves the issue\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Documentation-First Approach\n<\/h4>\n\n<p>Have goose write documentation before implementation.<\/p>\n\n<p><strong>Plan Before Code<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>You: goose, before we implement the payment system, write \n     technical documentation covering:\n\n     1. Architecture overview\n     2. API endpoint specifications\n     3. Data models\n     4. Security considerations\n     5. Error handling strategy\n     6. Testing approach\n\n     Once we agree on the design, we'll implement it.\n\n[Review and refine documentation]\n\nYou: Perfect! Now implement according to this spec.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Common Pitfalls and How to Avoid Them\n<\/h3>\n\n<h4>\n  \n  \n  Pitfall 1: Vague Instructions\n<\/h4>\n\n<p><strong>\u274c Problem:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, make the app better\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>\u2705 Solution:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, improve the app's performance by:\n- Optimizing database queries in the user service\n- Adding caching for frequently accessed data\n- Reducing bundle size by code-splitting\n- Implementing lazy loading for images\n\nStart with the database query optimization.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Pitfall 2: Assuming Goose Knows Your Codebase\n<\/h4>\n\n<p><strong>\u274c Problem:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, fix the bug in the auth module\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>\u2705 Solution:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, there's a bug in src\/auth\/login.js line 45. When users try to \nlogin with valid credentials, they get a 401 error. The issue appeared \nafter upgrading bcrypt from v4 to v5. Can you investigate and fix it?\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Pitfall 3: Not Providing Error Context\n<\/h4>\n\n<p><strong>\u274c Problem:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, my code isn't working\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>\u2705 Solution:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, I'm getting this error when running the tests:\n\nTypeError: Cannot read property 'length' of undefined\n    at UserService.validateEmail (src\/services\/user.js:23)\n\nThe error occurs when calling validateEmail with null input. \nHere's the relevant code: [paste code]\n\nFix the null handling and add validation.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Pitfall 4: Overloading a Single Prompt\n<\/h4>\n\n<p><strong>\u274c Problem:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, create a full e-commerce site with user auth, product catalog, \nshopping cart, payment processing, order management, admin dashboard, \nemail notifications, and analytics\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>\u2705 Solution:<\/strong><br>\nBreak it into phases (use chain-of-thought or task decomposition):<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, let's build an e-commerce site step by step. Phase 1: User \nauthentication and authorization. Let's start there.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Pitfall 5: Ignoring Model Limitations\n<\/h4>\n\n<p><strong>\u274c Problem:<\/strong><br>\nExpecting goose to know real-time information or access external resources it can't reach.<br>\n<strong>\u2705 Solution:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, I need to integrate with the Stripe API. Here's their latest \ndocumentation: [paste relevant docs]. Implement payment processing \nfollowing these guidelines.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Pitfall 6: Not Reviewing AI-Generated Code\n<\/h4>\n\n<p><strong>\u274c Problem:<\/strong><br>\nBlindly accepting and deploying Goose's code without review.<br>\n<strong>\u2705 Solution:<\/strong><\/p>\n\n<ul>\n<li>Always review generated code<\/li>\n<li>Run tests before committing<\/li>\n<li>Check for security vulnerabilities<\/li>\n<li>Verify edge cases are handled<\/li>\n<li>Ask Goose to explain complex logic\n<\/li>\n<\/ul>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, explain what this regex pattern does and why you chose this approach\n<\/code><\/pre>\n\n<\/div>\n\n<h4>\n  \n  \n  Pitfall 7: Forgetting to Specify Output Format\n<\/h4>\n\n<p><strong>\u274c Problem:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, document the API\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>\u2705 Solution<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, document the API in OpenAPI 3.0 format. Include:\n- All endpoints with methods\n- Request\/response schemas\n- Authentication requirements\n- Example requests and responses\n- Error codes and meanings\n\nOutput as a valid openapi.yaml file.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Optimizing for Different LLM Providers\n<\/h3>\n\n<p>Different models have different strengths. Adjust your approach based on your provider.<\/p>\n\n<h4>\n  \n  \n  GPT-4o (OpenAI)\n<\/h4>\n\n<p><strong>Strengths:<\/strong><\/p>\n\n<ul>\n<li>Excellent at following complex instructions<\/li>\n<li>Strong coding capabilities<\/li>\n<li>Good at understanding context<\/li>\n<\/ul>\n\n<p><strong>Optimization Tips:<\/strong><\/p>\n\n<ul>\n<li>Be specific and detailed<\/li>\n<li>Use structured prompts<\/li>\n<li>Leverage function calling for tool use\n<em><strong>Example<\/strong><\/em>\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, analyze the performance bottlenecks in src\/services\/data.js \nand propose specific optimizations. For each suggestion, explain:\n1. Current problem\n2. Proposed solution  \n3. Expected impact\n4. Implementation difficulty (1-5 scale)\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Claude (Anthropic)\n<\/h4>\n\n<p><strong>Strengths:<\/strong><\/p>\n\n<ul>\n<li>Excellent reasoning capabilities<\/li>\n<li>Strong at code analysis and refactoring<\/li>\n<li>Good at explaining complex concepts<\/li>\n<\/ul>\n\n<p><strong>Optimization Tips:<\/strong><\/p>\n\n<ul>\n<li>Ask for step-by-step reasoning<\/li>\n<li>Use chain-of-thought prompting<\/li>\n<li>Request detailed explanations\n<strong><em>Example<\/em><\/strong>\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, walk me through refactoring this legacy code. For each change:\n- Explain what the current code does\n- Identify the problem\n- Show the improved version\n- Explain why it's better\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Gemini (Google)\n<\/h4>\n\n<p><strong>Strengths:<\/strong><\/p>\n\n<ul>\n<li>Fast responses<\/li>\n<li>Good at code generation<\/li>\n<li>Strong multimodal capabilities<\/li>\n<\/ul>\n\n<p><strong>Optimization Tips:<\/strong><\/p>\n\n<ul>\n<li>Use clear, direct instructions<\/li>\n<li>Provide examples when possible<\/li>\n<li>Break complex tasks into steps<\/li>\n<\/ul>\n\n<p><em><strong>Example<\/strong><\/em><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, generate a React component for file upload. Requirements:\n- Drag-and-drop support\n- Progress indicators\n- Multiple file selection\n- File type validation\n\nShow me the complete implementation with TypeScript types.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Building Effective Workflows\n<\/h3>\n\n<h4>\n  \n  \n  The Debug Workflow\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>1. Describe the symptom\n   \"goose, users are getting 500 errors on the checkout page\"\n\n2. Provide context\n   \"This started after deploying the payment gateway update\"\n\n3. Share error details\n   [Paste error logs, stack traces]\n\n4. Request investigation\n   \"Investigate the cause and propose fixes\"\n\n5. Iterate on solution\n   \"That fix works, but add error handling for network timeouts\"\n\n6. Verify\n   \"Run the test suite to confirm the fix\"```\n\n\n#### The Feature Development Workflow\n\n\n```html\n1. High-level overview\n   \"goose, I need to add two-factor authentication\"\n\n2. Break into phases\n   \"Let's plan this in phases: setup, implementation, testing\"\n\n3. Design first\n   \"Start with the database schema and API design\"\n\n4. Implement incrementally\n   [Complete each phase before moving forward]\n\n5. Test continuously\n   \"Write tests for each component as we build\"\n\n6. Document\n   \"Add documentation for the completed feature\"\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  The Learning Workflow\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>1. State your knowledge level\n   \"goose, I'm new to GraphQL\"\n\n2. Ask for structured explanation\n   \"Explain GraphQL step by step, starting with the basics\"\n\n3. Request examples\n   \"Show me a practical example with our existing Express setup\"\n\n4. Practice with guidance\n   \"Let's implement a simple GraphQL endpoint together\"\n\n5. Review and refine\n   \"Review my implementation and suggest improvements\"\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  The Code Review Workflow\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>1. Set review criteria\n   \"goose, review this PR for:\n   - Code quality and readability\n   - Performance issues\n   - Security vulnerabilities\n   - Test coverage\n   - Documentation\"\n\n2. Request specific feedback\n   \"Focus especially on the error handling patterns\"\n\n3. Ask for alternatives\n   \"Are there better approaches I should consider?\"\n\n4. Implement suggestions\n   \"Make the changes you recommended\"\n\n5. Final verification\n   \"Review the updated code\"\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Measuring Success: Prompt Quality Checklist\n<\/h3>\n\n<p>Before sending a prompt, check:<\/p>\n\n<ol>\n<li>\n<strong>Clear objective<\/strong>: Does goose know exactly what you want?<\/li>\n<li> <strong>Sufficient context<\/strong>: Have you provided necessary background?<\/li>\n<li> <strong>Specific constraints<\/strong>: Are limitations and requirements stated?<\/li>\n<li> <strong>Appropriate scope<\/strong>: Is the task reasonable for one interaction?<\/li>\n<li> <strong>Output format specified<\/strong>: Does goose know how to deliver results?<\/li>\n<li> <strong>Success criteria<\/strong>: Can you evaluate if the response is good?<\/li>\n<li> <strong>Polite tone<\/strong>: Have you asked nicely?<\/li>\n<\/ol>\n\n<h4>\n  \n  \n  Quick Reference: Prompt Templates\n<\/h4>\n\n<p><strong>For Bug Fixes<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, there's a bug in [file\/function]. \n\n**Symptom:** [What's happening]\n**Expected:** [What should happen]\n**Context:** [When it started, recent changes]\n**Error:** [Paste error message\/logs]\n\nPlease debug and fix this issue.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>For New Features<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, implement [feature name].\n\n**Requirements:**\n- [Requirement 1]\n- [Requirement 2]\n- [Requirement 3]\n\n**Technical constraints:**\n- [Stack\/framework details]\n- [Performance requirements]\n- [Compatibility needs]\n\n**Acceptance criteria:**\n- [How to verify it works]\n\nPlease provide a complete implementation with tests.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>For Code Review<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, review this code:\n\n[Paste code or specify file]\n\n**Focus areas:**\n- [Performance]\n- [Security]\n- [Maintainability]\n- [Best practices]\n\nPlease provide:\n1. Issues found\n2. Severity of each issue\n3. Specific fixes\n4. Alternative approaches if applicable\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>For Refactoring<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>goose, refactor [file\/component].\n\n**Goals:**\n- [Improve readability]\n- [Better performance]\n- [Reduce complexity]\n\n**Constraints:**\n- [Must maintain backward compatibility]\n- [Cannot add dependencies]\n\n**Current issues:**\n- [Problem 1]\n- [Problem 2]\n\nShow the refactored code and explain the improvements.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>For Learning<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, I want to understand [concept].\n\n**My background:** [Your experience level]\n**Specific questions:** [What you're confused about]\n**Learning goal:** [What you want to achieve]\n\nPlease explain step by step, using examples relevant to \n[your tech stack\/project].\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Bonus: Real-World Prompting Examples\n<\/h3>\n\n<p>Let's look at some real-world scenarios and how to prompt effectively for each.<\/p>\n\n<h4>\n  \n  \n  Scenario 1: Debugging Production Issue\n<\/h4>\n\n<p><strong>Context<\/strong>: Your production API is experiencing intermittent 503 errors during peak traffic<br>\n<strong>Effective Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, we're experiencing 503 errors in production during peak traffic \n(~1000 req\/sec). \n\n**Environment:**\n- Node.js 18, Express, PostgreSQL\n- Load balanced across 4 instances\n- Redis for session storage\n\n**Observed behavior:**\n- Errors spike between 6-8 PM daily\n- Database connection pool shows no issues\n- Memory usage normal (<span class=\"nt\">&lt;<\/span> <span class=\"err\">70%)<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">CPU<\/span> <span class=\"na\">spikes<\/span> <span class=\"na\">to<\/span> <span class=\"err\">95%<\/span> <span class=\"na\">during<\/span> <span class=\"na\">error<\/span> <span class=\"na\">periods<\/span>\n\n<span class=\"na\">**Files<\/span> <span class=\"na\">to<\/span> <span class=\"na\">investigate:**<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">src<\/span><span class=\"err\">\/<\/span><span class=\"na\">middleware<\/span><span class=\"err\">\/<\/span><span class=\"na\">rateLimiter.js<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">src<\/span><span class=\"err\">\/<\/span><span class=\"na\">services<\/span><span class=\"err\">\/<\/span><span class=\"na\">cache.js<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">src<\/span><span class=\"err\">\/<\/span><span class=\"na\">db<\/span><span class=\"err\">\/<\/span><span class=\"na\">connection.js<\/span>\n\n<span class=\"na\">Please<\/span> <span class=\"na\">analyze<\/span> <span class=\"na\">these<\/span> <span class=\"na\">files<\/span><span class=\"err\">,<\/span> <span class=\"na\">identify<\/span> <span class=\"na\">the<\/span> <span class=\"na\">bottleneck<\/span><span class=\"err\">,<\/span> <span class=\"na\">and<\/span> <span class=\"na\">propose<\/span> <span class=\"na\">a<\/span> <span class=\"na\">fix.<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Why this works<\/strong><\/p>\n\n<ul>\n<li>Specific error type and occurrence pattern<\/li>\n<li>Complete technical context<\/li>\n<li>Observable metrics provided<\/li>\n<li>Directs investigation to likely culprits<\/li>\n<li>Clear request for analysis and solution<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Scenario 2: Implementing a New Feature\n<\/h4>\n\n<p><strong>Context<\/strong>: Adding a notification system to your application.<br>\n<strong>Effective Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, let's implement a notification system. Here's the plan:\n\n**Phase 1: Data Model Design**\n\nCreate database tables for:\n- Notifications (id, user_id, type, content, read_at, created_at)\n- Notification Preferences (user_id, email_enabled, push_enabled, frequency)\n\nUse PostgreSQL with Sequelize ORM following our existing model patterns \nin src\/models\/\n\n**Constraints:**\n- Must scale to millions of notifications\n- Support soft deletes\n- Include indexes for common queries (user_id + read_at)\n- Add created_at and updated_at timestamps\n\nLet's start with Phase 1. Show me the migration files and model definitions.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Follow-up prompts<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>[After Phase 1 complete]\n\ngoose, Phase 2: API Endpoints\n\nCreate REST endpoints:\n- POST \/api\/notifications - Create notification\n- GET \/api\/notifications - List user's notifications (paginated)\n- PATCH \/api\/notifications\/:id\/read - Mark as read\n- PATCH \/api\/notifications\/read-all - Mark all as read\n- DELETE \/api\/notifications\/:id - Delete notification\n\nFollow our controller \u2192 service \u2192 model pattern.\nInclude input validation using Joi.\nAdd appropriate error handling.\n\nShow implementation for all endpoints.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Scenario 3: Code Quality Improvement\n<\/h4>\n\n<p><strong>Context<\/strong>: Refactoring legacy JavaScript to TypeScript.<br>\n<strong>Effective Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, convert src\/utils\/validation.js to TypeScript.\n\n**Current file issues:**\n- No type safety\n- Unclear function signatures\n- Lacks input validation\n- No JSDoc comments\n- Uses var instead of const\/let\n\n**Requirements:**\n1. Add proper TypeScript types for all functions\n2. Create interfaces for complex objects\n3. Add comprehensive JSDoc with examples\n4. Improve error messages to be more descriptive\n5. Add input validation with helpful errors\n6. Export types for use in other files\n7. Maintain 100% backward compatibility\n\n**Code style:**\n- Use functional programming patterns\n- Prefer const over let\n- Use arrow functions for simple operations\n- Add unit tests for all exported functions\n\nShow the complete TypeScript implementation.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Scenario 4: Performance Optimization\n<\/h4>\n\n<p><strong>Context<\/strong>: Slow database queries affecting user experience.<br>\n<strong>Effective Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, optimize the slow queries in src\/services\/analytics.js\n\n**Performance requirements:**\n- Query execution time: <span class=\"nt\">&lt;<\/span> <span class=\"err\">100<\/span><span class=\"na\">ms<\/span> <span class=\"err\">(<\/span><span class=\"na\">currently<\/span> <span class=\"err\">2<\/span><span class=\"na\">-3<\/span> <span class=\"na\">seconds<\/span><span class=\"err\">)<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">Handle<\/span> <span class=\"na\">datasets<\/span> <span class=\"na\">up<\/span> <span class=\"na\">to<\/span> <span class=\"err\">100<\/span><span class=\"na\">k<\/span> <span class=\"na\">records<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">Support<\/span> <span class=\"na\">concurrent<\/span> <span class=\"na\">queries<\/span> <span class=\"err\">(50+<\/span> <span class=\"na\">users<\/span><span class=\"err\">)<\/span>\n\n<span class=\"na\">**Current<\/span> <span class=\"na\">approach:**<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">Multiple<\/span> <span class=\"na\">sequential<\/span> <span class=\"na\">database<\/span> <span class=\"na\">queries<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">No<\/span> <span class=\"na\">caching<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">Fetching<\/span> <span class=\"na\">all<\/span> <span class=\"na\">columns<\/span> <span class=\"na\">when<\/span> <span class=\"na\">only<\/span> <span class=\"na\">few<\/span> <span class=\"na\">needed<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">No<\/span> <span class=\"na\">pagination<\/span> <span class=\"na\">on<\/span> <span class=\"na\">large<\/span> <span class=\"na\">result<\/span> <span class=\"na\">sets<\/span>\n\n<span class=\"na\">**Available<\/span> <span class=\"na\">tools:**<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">PostgreSQL<\/span> <span class=\"err\">14<\/span> <span class=\"na\">with<\/span> <span class=\"na\">jsonb<\/span> <span class=\"na\">support<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">Redis<\/span> <span class=\"na\">for<\/span> <span class=\"na\">caching<\/span> <span class=\"err\">(<\/span><span class=\"na\">already<\/span> <span class=\"na\">configured<\/span><span class=\"err\">)<\/span>\n<span class=\"na\">-<\/span> <span class=\"na\">Database<\/span> <span class=\"na\">indexes<\/span> <span class=\"err\">(<\/span><span class=\"na\">can<\/span> <span class=\"na\">be<\/span> <span class=\"na\">added<\/span><span class=\"err\">)<\/span>\n\n<span class=\"na\">**Optimization<\/span> <span class=\"na\">goals:**<\/span>\n<span class=\"err\">1.<\/span> <span class=\"na\">Reduce<\/span> <span class=\"na\">database<\/span> <span class=\"na\">round<\/span> <span class=\"na\">trips<\/span>\n<span class=\"err\">2.<\/span> <span class=\"na\">Implement<\/span> <span class=\"na\">intelligent<\/span> <span class=\"na\">caching<\/span>\n<span class=\"err\">3.<\/span> <span class=\"na\">Add<\/span> <span class=\"na\">database<\/span> <span class=\"na\">indexes<\/span> <span class=\"na\">where<\/span> <span class=\"na\">helpful<\/span>\n<span class=\"err\">4.<\/span> <span class=\"na\">Use<\/span> <span class=\"na\">query<\/span> <span class=\"na\">optimization<\/span> <span class=\"na\">techniques<\/span>\n<span class=\"err\">5.<\/span> <span class=\"na\">Implement<\/span> <span class=\"na\">pagination<\/span> <span class=\"na\">for<\/span> <span class=\"na\">large<\/span> <span class=\"na\">datasets<\/span>\n\n<span class=\"na\">Analyze<\/span> <span class=\"na\">the<\/span> <span class=\"na\">current<\/span> <span class=\"na\">implementation<\/span><span class=\"err\">,<\/span> <span class=\"na\">identify<\/span> <span class=\"na\">bottlenecks<\/span><span class=\"err\">,<\/span> <span class=\"na\">and<\/span> <span class=\"na\">show<\/span> \n<span class=\"na\">optimized<\/span> <span class=\"na\">code<\/span> <span class=\"na\">with<\/span> <span class=\"na\">explanations<\/span> <span class=\"na\">for<\/span> <span class=\"na\">each<\/span> <span class=\"na\">improvement.<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Scenario 5: Security Audit\n<\/h4>\n\n<p><strong>Context<\/strong>: Preparing for a security audit.<br>\n<strong>Effective Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, perform a security audit on our authentication system.\n\n**Files to review:**\n- src\/auth\/login.js\n- src\/auth\/register.js\n- src\/auth\/resetPassword.js\n- src\/middleware\/authenticate.js\n\n**Security checklist:**\n1. SQL injection vulnerabilities\n2. XSS attack vectors\n3. CSRF protection\n4. Password storage (bcrypt usage, salt rounds)\n5. JWT token security (secret strength, expiration)\n6. Rate limiting on auth endpoints\n7. Input validation and sanitization\n8. Error message information leakage\n9. Session management security\n10. Brute force protection\n\nFor each file, identify:\n- **Critical issues**: Immediate security risks\n- **Warnings**: Potential vulnerabilities\n- **Recommendations**: Security best practices\n\nProvide specific code fixes for all issues found.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Scenario 6: Documentation Generation\n<\/h4>\n\n<p><strong>Context<\/strong>: Need comprehensive API documentation.<br>\n<strong>Effective Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code>goose, generate OpenAPI 3.0 documentation for our REST API.\n\n<span class=\"gs\">**Source files:**<\/span>\n<span class=\"p\">-<\/span> src\/routes\/<span class=\"err\">*<\/span>.js (all route definitions)\n<span class=\"p\">-<\/span> src\/controllers\/<span class=\"err\">*<\/span>.js (controller implementations)\n\n<span class=\"gs\">**Documentation requirements:**<\/span>\n<span class=\"p\">1.<\/span> All endpoints with methods, paths, descriptions\n<span class=\"p\">2.<\/span> Request body schemas with examples\n<span class=\"p\">3.<\/span> Response schemas for success and error cases\n<span class=\"p\">4.<\/span> Authentication requirements per endpoint\n<span class=\"p\">5.<\/span> Query parameters with types and constraints\n<span class=\"p\">6.<\/span> Path parameters with descriptions\n<span class=\"p\">7.<\/span> Example requests and responses for each endpoint\n<span class=\"p\">8.<\/span> Error codes with meaningful descriptions\n\n<span class=\"gs\">**Our API conventions:**<\/span>\n<span class=\"p\">-<\/span> Success: 200\/201 with data in response\n<span class=\"p\">-<\/span> Client errors: 400\/401\/403\/404 with { error: \"message\" }\n<span class=\"p\">-<\/span> Server errors: 500 with generic error message\n<span class=\"p\">-<\/span> Pagination: ?page=1&amp;limit=20 (default limit: 20, max: 100)\n<span class=\"p\">-<\/span> Authentication: Bearer token in Authorization header\n\nGenerate a complete openapi.yaml file following OpenAPI 3.0 spec.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Scenario 7: Test Coverage Improvement\n<\/h4>\n\n<p><strong>Context<\/strong>: Increasing test coverage before deployment.<br>\n<strong>Effective Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, add comprehensive test coverage for src\/services\/paymentService.js\n\n**Current coverage:** 45% (unacceptable)\n**Target coverage:** 90%+\n\n**Testing requirements:**\n1. Unit tests for all public methods\n2. Integration tests for payment gateway interactions\n3. Edge cases and error scenarios\n4. Mock external API calls (Stripe)\n5. Test success and failure paths\n6. Validate input handling\n7. Check error message clarity\n\n**Test structure to follow:**\n- Use Jest as testing framework\n- Follow AAA pattern (Arrange, Act, Assert)\n- Group tests by method using describe blocks\n- Use descriptive test names (it should...)\n- Mock external dependencies properly\n- Test one thing per test case\n\n**Specific scenarios to cover:**\n- Valid payment processing\n- Invalid payment details\n- Network failures\n- Timeout scenarios\n- Insufficient funds\n- Currency validation\n- Amount validation (positive, not zero, within limits)\n- Idempotency (duplicate payment prevention)\n\nShow complete test file with all test cases.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Scenario 8: Migration Planning\n<\/h4>\n\n<p><strong>Context<\/strong>: Migrating from REST to GraphQL.<br>\n<strong>Effective Prompt<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, help me plan our migration from REST to GraphQL.\n\n**Current state:**\n- 25 REST endpoints in Express\n- PostgreSQL database with Sequelize ORM\n- JWT authentication\n- ~10k daily API requests\n\n**Goals:**\n- Gradual migration (not big bang)\n- Maintain backward compatibility\n- Improve frontend data fetching efficiency\n- Reduce over-fetching and under-fetching\n\n**Phase 1: Planning**\n\nAnalyze our current REST API in src\/routes\/ and:\n\n1. Recommend which endpoints to migrate first (quick wins)\n2. Design GraphQL schema covering all current functionality\n3. Propose a migration strategy (parallel run vs incremental)\n4. Identify potential challenges and solutions\n5. Estimate complexity and timeline for each phase\n\n**Constraints:**\n- Cannot break existing mobile apps (still using REST)\n- Must maintain same authentication mechanism\n- Need monitoring to compare REST vs GraphQL performance\n- Team has limited GraphQL experience\n\nProvide detailed analysis with actionable recommendations.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Pro Tips from Experienced goose Users\n<\/h3>\n\n<h4>\n  \n  \n  Tip 1: Create Prompt Templates\n<\/h4>\n\n<p>Save your successful prompts as templates for similar tasks:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Save to ~\/.goose-prompts\/debug-template.md<\/span>\ngoose, debug the issue <span class=\"k\">in<\/span> <span class=\"o\">[<\/span>FILE].\n\n<span class=\"k\">**<\/span>Symptom:<span class=\"k\">**<\/span> <span class=\"o\">[<\/span>DESCRIPTION]\n<span class=\"k\">**<\/span>Expected:<span class=\"k\">**<\/span> <span class=\"o\">[<\/span>EXPECTED_BEHAVIOR]\n<span class=\"k\">**<\/span>Context:<span class=\"k\">**<\/span> <span class=\"o\">[<\/span>RECENT_CHANGES]\n<span class=\"k\">**<\/span>Error:<span class=\"k\">**<\/span> <span class=\"o\">[<\/span>ERROR_MESSAGE]\n\nPlease investigate and fix.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Tip 2: Use Session Context Strategically\n<\/h4>\n\n<p>Start sessions in the relevant directory to give goose proper context:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Navigate to the specific feature directory<\/span>\n<span class=\"nb\">cd <\/span>src\/features\/authentication\ngoose session\n\n<span class=\"c\"># goose now has context of auth-related files<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Tip 3: Leverage goose's Memory\n<\/h4>\n\n<p>With the Memory Extension enabled, teach Goose your preferences once:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, remember these coding standards:\n- Use async\/await, not callbacks or .then()\n- Prefer const over let, never use var\n- Always add TypeScript types\n- Include error handling in all async functions\n- Write tests for all new features\n- Add JSDoc comments for public APIs\n- Follow our naming: camelCase for functions, PascalCase for classes\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Tip 4: Progressive Disclosure\n<\/h4>\n\n<p>Don't dump all information at once. Start high-level, then drill down:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>You: goose, I need to optimize our database queries\n\ngoose: I can help with that. Which specific queries or operations \n      are slow?\n\nYou: The user search functionality takes 3+ seconds\n\ngoose: Let me analyze the search implementation. Which file contains \n      the search logic?\n\nYou: src\/services\/userService.js, method searchUsers()\n\ngoose: [Analyzes code] I found several optimization opportunities...\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Tip 5: Validate Before Accepting\n<\/h4>\n\n<p>Always ask goose to explain complex changes:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>You: [After Goose implements a complex algorithm]\n     goose, explain how this algorithm works and why you chose \n     this approach\n\ngoose: [Provides detailed explanation]\n\nYou: What are the time and space complexity trade-offs?\n\ngoose: [Explains Big O complexity and alternatives]\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Tip 7: Context Files\n<\/h4>\n\n<p>Create a <code>CONTEXT.md<\/code> in your project root with important information<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code><span class=\"gh\"># Project Context for AI Assistants<\/span>\n\n<span class=\"gu\">## Tech Stack<\/span>\n<span class=\"p\">-<\/span> Backend: Node.js 18, Express 4, PostgreSQL 14\n<span class=\"p\">-<\/span> Frontend: React 18, TypeScript 5, Tailwind CSS\n<span class=\"p\">-<\/span> Testing: Jest, React Testing Library\n\n<span class=\"gu\">## Coding Standards<\/span>\n<span class=\"p\">-<\/span> TypeScript for all new code\n<span class=\"p\">-<\/span> Functional programming preferred\n<span class=\"p\">-<\/span> Async\/await over promises\n<span class=\"p\">-<\/span> Comprehensive error handling required\n\n<span class=\"gu\">## Architecture Patterns<\/span>\n<span class=\"p\">-<\/span> Controllers handle HTTP, delegate to services\n<span class=\"p\">-<\/span> Services contain business logic\n<span class=\"p\">-<\/span> Models handle data access\n<span class=\"p\">-<\/span> Middleware for cross-cutting concerns\n\n<span class=\"gu\">## Common Commands<\/span>\n<span class=\"p\">-<\/span> npm run dev - Start development server\n<span class=\"p\">-<\/span> npm test - Run test suite\n<span class=\"p\">-<\/span> npm run lint - Check code style\n<span class=\"p\">-<\/span> npm run migrate - Run database migrations\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><em>Then reference it: \"goose, refer to <code>CONTEXT.m<\/code>d for our coding standards\"<\/em><\/p>\n\n<h4>\n  \n  \n  Tip 8: Error Log Analysis\n<\/h4>\n\n<p>When debugging, provide structured error information:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, analyze this error:\n\n**Stack Trace:**\n[Full stack trace]\n\n**Request Details:**\n- Method: POST\n- Endpoint: \/api\/users\/create\n- Body: { email: \"test@example.com\", name: \"Test User\" }\n- Headers: [Relevant headers]\n\n**Environment:**\n- Node version: 18.17.0\n- Dependencies: [Relevant package versions]\n- Environment: staging\n\n**Recent Changes:**\n- Updated user validation logic (commit abc123)\n- Migrated to new database schema (commit def456)\n\nWhat's causing this error and how do we fix it?\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Tip 9: Comparative Learning\n<\/h4>\n\n<p>Ask Goose to compare approaches when learning<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, I need to implement real-time features. Compare these approaches \nfor our use case:\n\n1. WebSockets\n2. Server-Sent Events (SSE)\n3. Long polling\n4. GraphQL Subscriptions\n\nOur requirements:\n- Bidirectional communication\n- 500+ concurrent connections\n- Mobile app support\n- Need to work through corporate firewalls\n\nCreate a comparison table with pros\/cons and recommendation.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Tip 10: Version-Specific Guidance\n<\/h4>\n\n<p>Specify versions to avoid deprecated solutions:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, implement OAuth2 authentication using Passport.js.\n\n**Important:** \n- Use Passport.js v0.6+ (not legacy versions)\n- Node.js 18 compatible syntax\n- Express 4 (not Express 5)\n- No deprecated methods\n\nShow current best practices as of 2025.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Common goose Workflows\n<\/h3>\n\n<h4>\n  \n  \n  Morning Debug Ritual\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Start your day by reviewing failures<\/span>\n<span class=\"nb\">cd<\/span> ~\/projects\/my-app\ngoose session\n\n<span class=\"o\">&gt;<\/span> goose, run the <span class=\"nb\">test <\/span>suite and summarize any failures\n\n<span class=\"o\">&gt;<\/span> <span class=\"o\">[<\/span>goose runs tests, identifies 3 failures]\n\n<span class=\"o\">&gt;<\/span> goose, <span class=\"nb\">let<\/span><span class=\"s1\">'s fix these one by one. Start with the authentication \n  test failure. Explain what'<\/span>s wrong, <span class=\"k\">then <\/span>fix it.\n\n<span class=\"o\">&gt;<\/span> <span class=\"o\">[<\/span>Fix, <span class=\"nb\">test<\/span>, verify]\n\n<span class=\"o\">&gt;<\/span> Great! Next failure...\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Code Review Workflow\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Before committing<\/span>\ngoose session\n\n<span class=\"o\">&gt;<\/span> goose, review my uncommitted changes <span class=\"k\">for<\/span>:\n  1. Potential bugs\n  2. Performance issues\n  3. Security vulnerabilities\n  4. Code style violations\n  5. Missing tests\n\n<span class=\"o\">&gt;<\/span> <span class=\"o\">[<\/span>goose analyzes git diff]\n\n<span class=\"o\">&gt;<\/span> goose, fix the issues you found\n\n<span class=\"o\">&gt;<\/span> <span class=\"o\">[<\/span>Verify fixes]\n\n<span class=\"o\">&gt;<\/span> goose, generate a descriptive commit message\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Learning New Technology\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose session\n\n<span class=\"o\">&gt;<\/span> goose, I need to learn Docker <span class=\"k\">for <\/span>our deployment. I know Node.js \n  well but haven<span class=\"s1\">'t used containers.\n\n  Teach me Docker by:\n  1. Explaining core concepts with Node.js analogies\n  2. Creating a Dockerfile for our Express app\n  3. Setting up docker-compose for our stack\n  4. Showing common commands I'<\/span>ll need\n\n  Let<span class=\"s1\">'s start with #1\n\n&gt; [Learn incrementally]\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Feature Development Sprint\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose session\n\n<span class=\"o\">&gt;<\/span> goose, feature: Add email notifications\n\n  Let<span class=\"s1\">'s work in sprints:\n\n  Sprint 1 (30 min): Design &amp; Planning\n  - Database schema\n  - API endpoints design\n  - Email template structure\n\n  Sprint 2 (45 min): Core Implementation\n  - Database models\n  - Email service\n  - API endpoints\n\n  Sprint 3 (30 min): Testing &amp; Polish\n  - Unit tests\n  - Integration tests\n  - Error handling\n\n  Start Sprint 1 now.\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Troubleshooting Your Prompts\n<\/h3>\n\n<h4>\n  \n  \n  If goose gives generic answers:\n<\/h4>\n\n<p><strong>Problem<\/strong>: \"I need help with my code\"<br>\n<strong>Fix<\/strong>: Be specific:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, the login function in src\/auth\/login.js (line 45-67) returns \nundefined instead of a user object when credentials are valid.\n\nExpected: { id, email, token }\nActual: undefined\n\nRecent changes: Upgraded bcrypt from v4 to v5\n\nDebug this issue.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  If Goose misunderstands\n<\/h4>\n\n<p><strong>Problem<\/strong>: goose solves a different problem<br>\n<strong>Fix<\/strong>: Clarify and redirect<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, I think we're not on the same page. Let me clarify:\n\nI DON'T need: A new authentication system\nI DO need: Fix the existing login that broke after the bcrypt upgrade\n\nFocus on why bcrypt.compare() might behave differently in v5.\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  If responses are too technical\n<\/h4>\n\n<p><strong>Problem<\/strong>: Overwhelming technical jargon<br>\n<strong>Fix<\/strong>: Adjust the level<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>goose, that explanation is too technical. Remember I'm primarily a \nfrontend developer learning backend.\n\nExplain the same thing but:\n- Use simpler terms\n- Compare to frontend concepts when possible\n- Focus on practical use over theory\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Final Thoughts: Growing with goose\n<\/h3>\n\n<p>Prompt engineering is a journey, not a destination. As you work more with goose, you'll develop intuition for what works. You'll find your own voice, create your own templates, and discover techniques that fit your workflow.<br>\nThe key principles remain constant:<\/p>\n\n<ul>\n<li>Clarity over cleverness<\/li>\n<li>Context is king<\/li>\n<li>Iteration is natural<\/li>\n<li>Politeness pays off<\/li>\n<\/ul>\n\n<p>Remember, goose is a tool that amplifies your capabilities. It won't replace your expertise, judgment, or creativity\u2014but it will make you significantly more productive when you learn to communicate effectively.<br>\nNow go forth and prompt with confidence! Your next goose session awaits, and with these techniques, you're well-equipped to make it your most productive yet.<\/p>\n\n<p><em>Happy coding with goose! \ud83e\udda2<\/em><\/p>\n\n<h3>\n  \n  \n  Conclusion\n<\/h3>\n\n<p>The best prompts feel natural, and the most important thing is keeping them clear and natural without overthinking, though adding a little structure can make a huge difference.<br>\nEffective prompt engineering isn't about memorizing magical phrases or following rigid formulas. It's about clear communication, iterative refinement, and understanding that goose is here to make your life easier<\/p>\n\n<h4>\n  \n  \n  Key Takeaways\n<\/h4>\n\n<ol>\n<li>\n<strong>Be specific<\/strong>: Vague prompts get vague results<\/li>\n<li>\n<strong>Provide context<\/strong>: Goose can't read your mind<\/li>\n<li>\n<strong>Iterate freely<\/strong>: First drafts rarely perfect; refine as you go<\/li>\n<li>\n<strong>Use examples<\/strong>: Show don't just tell when possible<\/li>\n<li>\n<strong>Break down complexity<\/strong>: Chain-of-thought for big tasks<\/li>\n<li>\n<strong>Be polite<\/strong>: It genuinely improves results<\/li>\n<li>\n<strong>Understand your model<\/strong>: Different LLMs need different approaches<\/li>\n<li>\n<strong>Review everything<\/strong>: AI is a tool, not a replacement for judgment<\/li>\n<\/ol>\n\n<h4>\n  \n  \n  Moving Forward\n<\/h4>\n\n<p>The next time you open a goose session:<\/p>\n\n<ul>\n<li>Start with clear intent<\/li>\n<li>Provide necessary context<\/li>\n<li>Experiment with different approaches<\/li>\n<li>Refine based on results<\/li>\n<li>Build on what works<\/li>\n<\/ul>\n\n<p>Remember, prompt engineering is a skill that improves with practice. Every interaction teaches you something about how to communicate more effectively with AI. Your prompts will naturally become better as you develop intuition for what works.<\/p>\n\n<h4>\n  \n  \n  Additional Resources\n<\/h4>\n\n<ul>\n<li><a href=\"https:\/\/block.github.io\/goose\/docs\/category\/getting-started\/\" rel=\"noopener noreferrer\">Official goose Documentation<\/a><\/li>\n<li>\n<a href=\"https:\/\/block.github.io\/goose\/blog\/2025\/03\/19\/better-ai-prompting\/\" rel=\"noopener noreferrer\">goose Blog - AI Prompting 101<\/a> <\/li>\n<li><a href=\"https:\/\/discord.com\/invite\/block-opensource\" rel=\"noopener noreferrer\">Community Discord<\/a><\/li>\n<li><a href=\"https:\/\/docs.claude.com\/en\/docs\/build-with-claude\/prompt-engineering\/overview\" rel=\"noopener noreferrer\">Anthropic Prompt Engineering Guide<\/a><\/li>\n<li><a href=\"https:\/\/platform.openai.com\/docs\/guides\/prompt-engineering\" rel=\"noopener noreferrer\">OpenAI Best Practices<\/a><\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Want to Learn More?\n<\/h4>\n\n<ul>\n<li>Read the first guide: <a href=\"https:\/\/dev.to\/lymah\/getting-started-with-goose-on-windows-30bh\">Getting Started with Goose on Windows<\/a>\n<\/li>\n<li>Join the community: <a href=\"https:\/\/discord.gg\/block-opensource\" rel=\"noopener noreferrer\">Discord<\/a> | <a href=\"https:\/\/github.com\/block\/goose\/discussions\" rel=\"noopener noreferrer\">GitHub Discussions<\/a>\n<\/li>\n<li>Share your prompting tips: We'd love to hear what works for you!<\/li>\n<li><a href=\"https:\/\/github.com\/Lymah123\" rel=\"noopener noreferrer\">Follow for more goose content<\/a><\/li>\n<\/ul>\n\n<p>Have questions or additional prompting tips? Drop them in the comments below!<\/p>\n\n","category":["goose","opensource","ai","llm"]},{"title":"Getting started with goose on Windows","pubDate":"Tue, 14 Oct 2025 11:47:27 +0000","link":"https:\/\/dev.to\/lymah\/getting-started-with-goose-on-windows-30bh","guid":"https:\/\/dev.to\/lymah\/getting-started-with-goose-on-windows-30bh","description":"<h2>\n  \n  \n  Table of Contents\n<\/h2>\n\n<ul>\n<li>Introduction<\/li>\n<li>What is goose?<\/li>\n<li>\nWindows Installation Options\n\n<ul>\n<li>A. Option 1: goose Desktop (Recommended for Beginners)<\/li>\n<li>Installation Steps<\/li>\n<li>A walkthrough<\/li>\n<li>First Launch<\/li>\n<li>B. Option 2: goose CLI (For Power Users)<\/li>\n<li>Method 1: Native Windows Installation<\/li>\n<li>Critical Windows-Specific Note<\/li>\n<li>Method 2: Windows Subsystem for Linux (WSL)<\/li>\n<li>Installation Steps<\/li>\n<li>WSL Considerations<\/li>\n<li>Windows-Specific API Key Setup<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nChoosing an LLM Provider\n\n<ul>\n<li>Rate Limits and API Management<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nRunning Your First goose Session\n\n<ul>\n<li>Desktop Usage<\/li>\n<li>CLI Usage<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nWindows-Specific Optimizations and Best Practices\n\n<ul>\n<li>Path and Directory Considerations<\/li>\n<li>Permission Issues<\/li>\n<li>Performance Tips<\/li>\n<li>Firewall and Network Configuration<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nWorking with Extensions\n\n<ul>\n<li>Managing Extensions<\/li>\n<li>Useful Extensions for Windows Developers<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nTroubleshooting Common Windows Issues\n\n<ul>\n<li>Issue: Command Not Found After Installation<\/li>\n<li>Issue: API Key Not Persisting<\/li>\n<li>Issue: Slow Performance or Timeouts<\/li>\n<li>Issue: Desktop App Won't Launch<\/li>\n<li>Issue: WSL File Access Errors<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nUpdating goose\n\n<ul>\n<li>Desktop Update<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nBest Practices for Windows Users\n\n<ul>\n<li>Development Workflow Integration<\/li>\n<li>Security and Privacy<\/li>\n<li>Cost Management<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>\n\nAdvanced Configuration\n\n<ul>\n<li>Shared Configuration<\/li>\n<li>Multiple Providers<\/li>\n<li>Conclusion<\/li>\n<li>Additional Resources<\/li>\n<\/ul>\n\n\n<\/li>\n\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Introduction\n<\/h2>\n\n<p>goose is an open source, extensible AI agent that transforms how developers work by going beyond simple code suggestions. It can install packages, execute commands, edit files, and test code, all powered by your choice of LLM. While goose has traditionally been more prevalent on <em><strong>macOS<\/strong><\/em> and <strong><em>Linux<\/em><\/strong>, <strong>Windows<\/strong> support has matured significantly, making it a powerful tool for Windows developers.<br>\nThis comprehensive guide will walk you through installing, configuring, and optimizing Goose on Windows systems, addressing platform-specific challenges and best practices.<\/p>\n<h2>\n  \n  \n  What is goose?\n<\/h2>\n\n<p>Before diving into installation, let's understand what makes goose special. goose is an AI-powered development assistant that operates locally in your environment, integrating seamlessly with your existing tools. Unlike traditional AI coding assistants that only suggest code, goose can:<\/p>\n\n<ul>\n<li>Execute commands in your terminal<\/li>\n<li>Read and modify files in your project<\/li>\n<li>Install dependencies and run tests<\/li>\n<li>Interact with APIs and databases<\/li>\n<li>Work with any LLM provider you choose<\/li>\n<\/ul>\n\n<p>The tool is available in two forms: a desktop application with a graphical interface and a command-line interface (CLI) for terminal enthusiasts.<\/p>\n<h2>\n  \n  \n  Windows Installation Options\n<\/h2>\n\n<p>goose offers multiple installation paths on Windows, each suited to different workflows and preferences. Let's explore both options.<\/p>\n<h3>\n  \n  \n  A. Option 1: goose Desktop (Recommended for Beginners)\n<\/h3>\n\n<p>The desktop application provides the easiest entry point, especially if you prefer a visual interface or are new to command-line tools.<\/p>\n<h3>\n  \n  \n  Installation Steps:\n<\/h3>\n\n<ol>\n<li>Navigate to the <a href=\"https:\/\/block.github.io\/goose\/docs\/getting-started\/installation\/\" rel=\"noopener noreferrer\">official goose installation page<\/a>\n<\/li>\n<li>Download the Windows ZIP file for goose Desktop<\/li>\n<li>Extract the ZIP file to a location of your choice (e.g., <code>C:\\Program Files\\goose or your user directory<\/code>)<\/li>\n<li>Run the executable file to launch the application<\/li>\n<li>Keep the executable accessible\u2014consider creating a desktop shortcut or pinning it to your taskbar<\/li>\n<\/ol>\n<h3>\n  \n  \n  A walkthrough\n<\/h3>\n\n<ol>\n<li>This is what the extracted file will look like. Click on the file with the <code>goose<\/code> icon from the folder.\n<img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frxmyj02xqc6zbcfdx93i.png\" alt=\"Image 1\" width=\"800\" height=\"449\">\n<\/li>\n<li>Create a shortcut for easier access:\n\n<ul>\n<li>Right-click on the <code>goose<\/code>file.\n<img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fse7j26v7deeawyneykzc.png\" alt=\"Image 2\" width=\"800\" height=\"449\">\n<\/li>\n<li>Select \"Send to\" \u2192 \"Desktop (create shortcut)\"\n<img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzb5k6lvypuzit6awyijd.png\" alt=\"Image 3\" width=\"800\" height=\"449\">\n<\/li>\n<li>Now you can launch goose from your desktop.\n<img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F380nnzjg6biz97h4i44s.png\" alt=\"Image 4\" width=\"800\" height=\"449\">\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h2>\n  \n  \n  First Launch\n<\/h2>\n\n<p>When you first open goose Desktop, you'll be greeted with a provider configuration screen. This is where you'll select your LLM provider and enter your API key. The interface is intuitive:<br>\n<a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmlce59nd7hgnb4hjc1q.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmlce59nd7hgnb4hjc1q.png\" alt=\"Image 5\" width=\"800\" height=\"449\"><\/a><\/p>\n\n<ul>\n<li>Use the provider dropdown to select your preferred service (OpenAI, Google Gemini, Anthropic Claude, etc.)\n<img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs0u7a5c6r0bxxa7ksjf6.png\" alt=\"Image 6\" width=\"800\" height=\"449\">\n<\/li>\n<li>Authorize your AI agent.\n<img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw0kc7m3db7cz4z4jk2w.png\" alt=\"Image 7\" width=\"800\" height=\"449\">\n<\/li>\n<li>Authorize your created API key when prompted\n<img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fav3k0h20s0ch6c4wkahx.png\" alt=\"Image 8\" width=\"800\" height=\"449\">\n<\/li>\n<li>Click Submit to complete the setup\n<img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsqyhaqcezuq242fwc7h.png\" alt=\"Image 9\" width=\"800\" height=\"449\">\n<\/li>\n<li>Boom! Your goose Desktop is launched.\n<img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzu4mxjyfr9vr9m01nhzi.png\" alt=\"Image 10\" width=\"800\" height=\"449\">\n<\/li>\n<\/ul>\n\n<blockquote>\n<p>The desktop interface features a clean chat-style interface where you can type instructions, upload files, do all sort of things and goose will execute tasks immediately.<\/p>\n<\/blockquote>\n<h2>\n  \n  \n  B. Option 2: goose CLI (For Power Users)\n<\/h2>\n\n<p>The CLI version integrates directly with your terminal workflow, making it ideal for developers who live in the command line. Windows users have three approaches for running the goose CLI.<\/p>\n<h3>\n  \n  \n  Method 1: Native Windows Installation\n<\/h3>\n\n<p>This method installs goose natively on Windows, providing the best performance and integration.<br>\nPrerequisites:<br>\nYou'll need one of these environments:<\/p>\n\n<ul>\n<li>Git Bash (recommended): Comes bundled with Git for Windows<\/li>\n<li>MSYS2: A Unix-like environment for Windows<\/li>\n<li>PowerShell: Built into Windows 10\/11<\/li>\n<\/ul>\n\n<p>The installation script requires <code>curl<\/code> and <code>unzip<\/code> to be available. Git Bash includes these by default, making it the simplest choice for most users.<\/p>\n\n<p><strong>Installation:<\/strong><br>\nOpen Git Bash, MSYS2, or PowerShell and run:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>curl <span class=\"nt\">-fsSL<\/span> https:\/\/github.com\/block\/goose\/releases\/download\/stable\/download_cli.sh | bash\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>To install without interactive configuration, disable <code>CONFIGURE<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>curl <span class=\"nt\">-fsSL<\/span> https:\/\/github.com\/block\/goose\/releases\/download\/stable\/download_cli.sh | <span class=\"nv\">CONFIGURE<\/span><span class=\"o\">=<\/span><span class=\"nb\">false <\/span>bash\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Once the installation was successful. Now you need to add the binary to your PATH. Since you're using Git Bash on Windows, add this line to your <code>~\/.bashrc<\/code>:<br>\n<code>export PATH=\"\/c\/Users\/user\/.local\/bin:$PATH\"<\/code><\/p>\n\n<p>Here's how to do it:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Add to .bashrc<\/span>\n<span class=\"nb\">echo<\/span> <span class=\"s1\">'export PATH=\"\/c\/Users\/user\/.local\/bin:$PATH\"'<\/span> <span class=\"o\">&gt;&gt;<\/span> ~\/.bashrc\n\n<span class=\"c\"># Reload your shell<\/span>\n<span class=\"nb\">source<\/span> ~\/.bashrc\n\n<span class=\"c\"># Verify goose is now available<\/span>\ngoose <span class=\"nt\">--version<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri6qq7uk1v6h1s5kdhir.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri6qq7uk1v6h1s5kdhir.png\" alt=\"Image 11\" width=\"800\" height=\"449\"><\/a><\/p>\n\n<p>After reloading, run the configuration:<br>\n<code>goose configure<\/code><\/p>\n\n<p><strong><em>Configuring Your LLM Provider<\/em><\/strong><br>\ngoose works with multiple LLM providers, giving you flexibility in terms of cost, performance, and features. Here's how to set up your provider on Windows.<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Folh8c30je6dv6yra329y.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Folh8c30je6dv6yra329y.png\" alt=\"Image 12\" width=\"800\" height=\"233\"><\/a><\/p>\n\n<p>Follow the prompts to complete the configuration until you see a successful configuration in your terminal.<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqnlr2daz3n0i2ysgv9d.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqnlr2daz3n0i2ysgv9d.png\" alt=\"Image 13\" width=\"800\" height=\"291\"><\/a><\/p>\n\n<p>Start interacting with goose in your terminal with is command. <code>goose start<\/code><\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17cbdcfxtswt9zivolys.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17cbdcfxtswt9zivolys.png\" alt=\"Image x\" width=\"800\" height=\"368\"><\/a><\/p>\n\n<p><em><strong>You can now:<\/strong><\/em><\/p>\n\n<ul>\n<li>Ask questions about the codebase<\/li>\n<li>Request code changes<\/li>\n<li>Generate tests<\/li>\n<li>Review code<\/li>\n<li>Get explanations<\/li>\n<\/ul>\n\n<p><strong><em>Try some commands like:<\/em><\/strong><\/p>\n\n<ul>\n<li>\"What can you do?\"<\/li>\n<li>\"Explain the structure of this project\"<\/li>\n<li>\"Help me understand how the agent system works\"<\/li>\n<li>\"Show me the available MCP extensions\"\nThe context bar shows token usage: <code>\u25cb\u25cb\u25cb\u25cb\u25cb\u25cb\u25cb\u25cb\u25cb\u25cb 0% (0\/400000 tokens)<\/code>\n<\/li>\n<\/ul>\n\n<p><strong><em>Tips:<\/em><\/strong><\/p>\n\n<ul>\n<li>Press Enter to send your message<\/li>\n<li>Press Ctrl-J for a new line (multi-line input)<\/li>\n<li>Type your instructions or questions at the ( O)&gt; prompt<\/li>\n<\/ul>\n<h2>\n  \n  \n  Critical Windows-Specific Note\n<\/h2>\n\n<p>When prompted during configuration, choose NOT to store credentials in the keyring. Windows keyring integration can be problematic with goose. Instead, you'll set your API keys as environment variables.<\/p>\n<h3>\n  \n  \n  Method 2: Windows Subsystem for Linux (WSL)\n<\/h3>\n\n<p>While the native installation is recommended, WSL provides a full Linux environment that some developers prefer.<\/p>\n<h2>\n  \n  \n  Installation Steps\n<\/h2>\n\n<ol>\n<li>Open PowerShell as Administrator<\/li>\n<li>Install WSL with the default Ubuntu distribution:\n<\/li>\n<\/ol>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight powershell\"><code><span class=\"n\">wsl<\/span><span class=\"w\"> <\/span><span class=\"nt\">--install<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n<ol>\n<li>Restart your computer if prompted<\/li>\n<li>Launch Ubuntu:\n<\/li>\n<\/ol>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>wsl <span class=\"nt\">-d<\/span> Ubuntu\n<\/code><\/pre>\n\n<\/div>\n\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyq4ry5gv8eep535qye7t.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyq4ry5gv8eep535qye7t.png\" alt=\"Image xx\" width=\"800\" height=\"449\"><\/a><\/p>\n\n<ol>\n<li>Install goose in the Linux environment:\n<\/li>\n<\/ol>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>curl <span class=\"nt\">-fsSL<\/span> https:\/\/github.com\/block\/goose\/releases\/download\/stable\/download_cli.sh | bash\n<\/code><\/pre>\n\n<\/div>\n\n\n<p>If you encounter extraction errors, install bzip2:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">sudo <\/span>apt update <span class=\"o\">&amp;&amp;<\/span> <span class=\"nb\">sudo <\/span>apt <span class=\"nb\">install <\/span>bzip2 <span class=\"nt\">-y<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  WSL Considerations\n<\/h2>\n\n<ul>\n<li>File system performance can be slower when working with files in Windows directories (accessed via <code>\/mnt\/c\/<\/code>)<\/li>\n<li>Use WSL's native file system (<code>~\/<\/code> in Ubuntu) for better performance<\/li>\n<li>You'll need to launch WSL each time you want to use goose<\/li>\n<li>Windows and WSL maintain separate environments, which can complicate some workflows<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Windows-Specific API Key Setup\n<\/h3>\n\n<p>On Windows (especially with native installation), keyring storage can be unreliable. The best practice is to use environment variables.<br>\nSetting Environment Variables:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">export <\/span><span class=\"nv\">OPENAI_API_KEY<\/span><span class=\"o\">=<\/span>your_actual_api_key_here\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>To make this permanent, add it to your bash configuration:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">echo<\/span> <span class=\"s1\">'export PATH=\"$HOME\/.local\/bin:$PATH\"'<\/span> <span class=\"o\">&gt;&gt;<\/span> ~\/.bashrc\n<span class=\"nb\">echo<\/span> <span class=\"s1\">'export OPENAI_API_KEY=your_actual_api_key_here'<\/span> <span class=\"o\">&gt;&gt;<\/span> ~\/.bashrc\n<span class=\"nb\">source<\/span> ~\/.bashrc\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>For PowerShell (session-only)<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight powershell\"><code><span class=\"nv\">$<\/span><span class=\"nn\">env<\/span><span class=\"p\">:<\/span><span class=\"nv\">OPENAI_API_KEY<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"your_actual_api_key_here\"<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>For PowerShell (permanent)<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight powershell\"><code><span class=\"p\">[<\/span><span class=\"n\">System.Environment<\/span><span class=\"p\">]::<\/span><span class=\"n\">SetEnvironmentVariable<\/span><span class=\"p\">(<\/span><span class=\"s1\">'OPENAI_API_KEY'<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"s1\">'your_actual_api_key_here'<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"s1\">'User'<\/span><span class=\"p\">)<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p>After setting the environment variable, run <code>goose configure<\/code> again. goose will detect the existing environment variable and display:<\/p>\n\n<p><code>\u25cf OPENAI_API_KEY is set via environment variable<\/code><\/p>\n\n<h2>\n  \n  \n  Choosing an LLM Provider\n<\/h2>\n\n<p>goose supports numerous providers, each with different strengths:<br>\n<strong>Free\/Low-Cost Options<\/strong><\/p>\n\n<ul>\n<li>Google Gemini: Offers a generous free tier, excellent for getting started<\/li>\n<li>Groq: Fast inference with limited free usage<\/li>\n<\/ul>\n\n<p><strong>Premium Options<\/strong><\/p>\n\n<ul>\n<li>OpenAI: GPT-4o and o1 models, industry-leading performance<\/li>\n<li>Anthropic Claude: Strong reasoning and coding capabilities<\/li>\n<li>Tetrate Agent Router Service: Managed routing with $10 in free credits for new users<\/li>\n<\/ul>\n\n<p>Consider your needs:<\/p>\n\n<ul>\n<li>Starting out? Use Google Gemini's free tier<\/li>\n<li>Professional development? GPT-4o or Claude Sonnet provide excellent results<\/li>\n<li>Budget-conscious? Monitor your usage and set up billing alerts<\/li>\n<\/ul>\n<h3>\n  \n  \n  Rate Limits and API Management\n<\/h3>\n\n<p>Most providers implement rate limits on API usage. This is especially important to understand when using goose, as complex tasks may generate multiple API calls in quick succession.<\/p>\n\n<p><strong><em>Best Practices:<\/em><\/strong><\/p>\n\n<ul>\n<li>Start with smaller, focused tasks to understand usage patterns<\/li>\n<li>Monitor your API usage through your provider's dashboard<\/li>\n<li>Set up billing alerts to avoid unexpected charges<\/li>\n<li>Consider using cheaper models for routine tasks and premium models for complex work<\/li>\n<li>Use goose's multi-model configuration to optimize cost and performance<\/li>\n<\/ul>\n<h2>\n  \n  \n  Running Your First goose Session\n<\/h2>\n\n<p>As I mentioned above, I will make Desktop, CLI, and general explanation in this section.<\/p>\n\n<p>With configuration complete, you're ready to start using goose. The experience differs slightly between Desktop and CLI.<\/p>\n<h3>\n  \n  \n  Desktop Usage\n<\/h3>\n\n<p>Launch the goose Desktop application. After the initial provider setup, you'll see a chat interface. Simply type your request in the input field:<br>\n<strong>Example Tasks:<\/strong><\/p>\n\n<ul>\n<li>\"Create a Python script that fetches weather data from an API\"<\/li>\n<li>\"Review the code in src\/main.py and suggest improvements\"<\/li>\n<li>\"Set up a new React project with TypeScript\"<\/li>\n<li>\"Debug the error in my test suite\"\n<em>goose will process your request, execute necessary commands, and provide results directly in the interface.<\/em>\n<\/li>\n<\/ul>\n<h3>\n  \n  \n  CLI Usage\n<\/h3>\n\n<p>Navigate to your project directory in your terminal (Git Bash, MSYS2, or PowerShell) and start a session:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">cd<\/span> \/c\/Users\/YourName\/projects\/my-project\ngoose session\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>You'll enter an interactive session where you can converse with goose. The AI agent has full context of your current directory and can execute commands, read files, and make modifications.<\/p>\n\n<p><strong>Example Interaction:<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>You: Create a new FastAPI project with basic CRUD endpoints for a todo app\n\ngoose: I'll help you set up a FastAPI project with CRUD endpoints. Let me start by creating the project structure...\n\n[goose creates files, installs dependencies, and sets up the project]\n\ngoose: I've created a complete FastAPI project with:\n- Project structure with proper organization\n- CRUD endpoints for todos (GET, POST, PUT, DELETE)\n- Pydantic models for validation\n- In-memory storage (ready to connect to a database)\n- requirements.txt with FastAPI and Uvicorn\n\nYou can run the server with: uvicorn main:app --reload\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>To exit a session, press <code>Ctrl+C<\/code>.<\/p>\n\n<h2>\n  \n  \n  Windows-Specific Optimizations and Best Practices\n<\/h2>\n\n<h3>\n  \n  \n  Path and Directory Considerations\n<\/h3>\n\n<p>Windows uses backslashes <code>(\\)<\/code> for paths, while Unix-like systems use forward slashes <code>(\/)<\/code>. When using Git Bash or MSYS2, you'll typically use Unix-style paths:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># Windows path<\/span>\nC:<span class=\"se\">\\U<\/span>sers<span class=\"se\">\\Y<\/span>ourName<span class=\"se\">\\p<\/span>rojects<span class=\"se\">\\a<\/span>pp\n\n<span class=\"c\"># Git Bash\/MSYS2 equivalent<\/span>\n\/c\/Users\/YourName\/projects\/app\n\n<span class=\"c\"># PowerShell (use Windows paths)<\/span>\nC:<span class=\"se\">\\U<\/span>sers<span class=\"se\">\\Y<\/span>ourName<span class=\"se\">\\p<\/span>rojects<span class=\"se\">\\a<\/span>pp\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>goose handles path conversions automatically in most cases, but being aware of this helps troubleshoot issues.<\/p>\n\n<h3>\n  \n  \n  Permission Issues\n<\/h3>\n\n<p>Windows security can sometimes interfere with goose's file operations. If you encounter permission errors:<\/p>\n\n<ul>\n<li>Run as Administrator: Right-click your terminal and select \"Run as Administrator\"<\/li>\n<li>Check folder permissions: Ensure your user account has full control over the project directory<\/li>\n<li>Antivirus software: Some antivirus programs flag script execution; you may need to add exclusions<\/li>\n<\/ul>\n\n<p>The <code>~\/.config<\/code> directory is particularly important. goose stores configuration and logs here. If the Desktop app doesn't launch or shows no window, verify this directory has read and write permissions.<\/p>\n\n<h2>\n  \n  \n  Performance Tips\n<\/h2>\n\n<ul>\n<li>Use SSD storage: Place your projects on an SSD for faster file operations<\/li>\n<li>Disable real-time scanning: Configure antivirus to exclude your development directories<\/li>\n<li>Git Bash vs PowerShell: Git Bash generally provides better compatibility with Unix-oriented tools<\/li>\n<li>Resource allocation: goose uses LLM APIs that may take seconds to respond; be patient with complex requests<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Firewall and Network Configuration\n<\/h3>\n\n<p>goose makes HTTPS requests to LLM provider APIs. Ensure:<\/p>\n\n<ul>\n<li>Windows Firewall allows outbound HTTPS connections<\/li>\n<li>Corporate proxy settings are configured if necessary<\/li>\n<li>VPN software doesn't block API access<\/li>\n<\/ul>\n\n<p>For corporate environments, you may need to configure proxy <br>\nsettings in your environment variables:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">export <\/span><span class=\"nv\">HTTP_PROXY<\/span><span class=\"o\">=<\/span>http:\/\/proxy.company.com:8080\n<span class=\"nb\">export <\/span><span class=\"nv\">HTTPS_PROXY<\/span><span class=\"o\">=<\/span>http:\/\/proxy.company.com:8080\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Working with Extensions\n<\/h2>\n\n<p>goose's extensibility is one of its most powerful features. Extensions add new capabilities, from browser automation to specialized development tools.<\/p>\n\n<h3>\n  \n  \n  Managing Extensions\n<\/h3>\n\n<p><strong>CLI<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose configure\n<span class=\"c\"># Select \"Configure Extensions\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Desktop<\/strong><\/p>\n\n<ol>\n<li>Click the menu button (top-left)<\/li>\n<li>Open Settings<\/li>\n<li>Navigate to Extensions<\/li>\n<li>Add, configure, or toggle extensions<\/li>\n<\/ol>\n\n<h3>\n  \n  \n  Useful Extensions for Windows Developers\n<\/h3>\n\n<ul>\n<li>\n<strong>Computer Controller<\/strong>: Enables browser automation and UI interaction (useful for testing web apps)<\/li>\n<li>\n<strong>Developer Tools<\/strong>: Enhanced code analysis and refactoring<\/li>\n<li>\n<strong>Database Extensions<\/strong>: Direct database queries and management<\/li>\n<\/ul>\n\n<p>Extensions are stored in the shared configuration file at <code>~\/.config\/goose\/config.yaml<\/code>, so they work across both Desktop and CLI interfaces.<\/p>\n\n<h2>\n  \n  \n  Troubleshooting Common Windows Issues\n<\/h2>\n\n<h3>\n  \n  \n  Issue: Command Not Found After Installation\n<\/h3>\n\n<p><strong>Problem<\/strong>: After installing, typing goose returns \"command not found\"<br>\n<strong>Solution<\/strong>:<\/p>\n\n<ol>\n<li>Ensure <code>~\/.local\/bin<\/code> is in your PATH:\n<\/li>\n<\/ol>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">echo<\/span> <span class=\"s1\">'export PATH=\"$HOME\/.local\/bin:$PATH\"'<\/span> <span class=\"o\">&gt;&gt;<\/span> ~\/.bashrc\n   <span class=\"nb\">source<\/span> ~\/.bashrc\n<\/code><\/pre>\n\n<\/div>\n\n\n<ol>\n<li>Restart your terminal<\/li>\n<li>Verify installation:\n<\/li>\n<\/ol>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>which goose\n   goose <span class=\"nt\">--version<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n<h3>\n  \n  \n  Issue: API Key Not Persisting\n<\/h3>\n\n<p><strong>Problem<\/strong>: goose keeps asking for your API key each session<br>\n<strong>Solution<\/strong>:<br>\nThis typically happens when keyring storage fails. Use environment variables instead (see the configuration section above). Make sure to add the export command to your <code>~\/.bashrc<\/code> file for permanence.<\/p>\n<h3>\n  \n  \n  Issue: Slow Performance or Timeouts\n<\/h3>\n\n<p><strong>Problem<\/strong>: goose takes a very long time to respond or times out<br>\n<strong>Solution<\/strong>:<\/p>\n\n<ul>\n<li>Check your internet connection and API provider status<\/li>\n<li>Some models are slower than others; try a faster model (e.g., GPT-4o-mini instead of GPT-4o)<\/li>\n<li>Check if you've hit rate limits with your provider<\/li>\n<li>Increase timeout settings in extensions if applicable<\/li>\n<\/ul>\n<h3>\n  \n  \n  Issue: Desktop App Won't Launch\n<\/h3>\n\n<p><strong>Problem<\/strong>: goose Desktop executable runs but no window appears<br>\n<strong>Solution<\/strong>:<\/p>\n\n<ul>\n<li>Check <code>~\/.config directory<\/code> permissions<\/li>\n<li>Look for logs in <code>~\/.config\/goose\/logs\/<\/code>\n<\/li>\n<li>Try running from a terminal to see error messages<\/li>\n<li>Ensure antivirus isn't blocking the application<\/li>\n<\/ul>\n<h3>\n  \n  \n  Issue: WSL File Access Errors\n<\/h3>\n\n<p><strong>Problem:<\/strong> goose can't access files in Windows directories<br>\n<strong>Solution:<\/strong><\/p>\n\n<ul>\n<li>Use the <code>\/mnt\/c\/<\/code> path to access Windows drives from WSL<\/li>\n<li>Copy projects to WSL's native file system for better performance<\/li>\n<li>Ensure proper line ending configuration (Git's <code>core.autocrlf<\/code> setting)<\/li>\n<\/ul>\n<h2>\n  \n  \n  Updating goose\n<\/h2>\n\n<p>Keep goose up to date to benefit from bug fixes and new features.<br>\n<strong>CLI Update<\/strong><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose update\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Desktop Update\n<\/h3>\n\n<p>Download the latest version from the releases page and replace your existing installation. The update process is straightforward since all configuration is stored separately in <code>~\/.config\/goose\/<\/code>.<\/p>\n\n<h2>\n  \n  \n  Best Practices for Windows Users\n<\/h2>\n\n<h3>\n  \n  \n  Development Workflow Integration\n<\/h3>\n\n<ul>\n<li>\n<strong>Use Git Bash<\/strong>: For the most seamless experience with Unix-oriented development tools<\/li>\n<li>\n<strong>Organize projects<\/strong>: Keep projects in a dedicated directory with short paths (e.g., <code>C:\\dev\\projects\\<\/code>)<\/li>\n<li>\n<strong>Version control<\/strong>: Always use Git to track changes goose makes to your code<\/li>\n<li>\n<strong>Review AI changes<\/strong>: Don't blindly accept all suggestions; understand what goose is doing<\/li>\n<li>\n<strong>Start small<\/strong>: Begin with simple tasks to build confidence before tackling complex projects<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Security and Privacy\n<\/h3>\n\n<ul>\n<li>\n<strong>API key protection<\/strong>: Never commit API keys to version control<\/li>\n<li>\n<strong>Sensitive data<\/strong>: Be cautious when working with projects containing credentials or private information<\/li>\n<li>\n<strong>Code review<\/strong>: Always review code goose generates, especially for security-critical applications<\/li>\n<li>\n<strong>Local execution<\/strong>: Goose runs locally, but it sends code context to LLM APIs; understand your provider's data policies<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Cost Management\n<\/h3>\n\n<ul>\n<li>\n<strong>Use appropriate models<\/strong>: Don't use GPT-4o for simple tasks when GPT-4o-mini will suffice<\/li>\n<li>\n<strong>Break down large tasks<\/strong>: Instead of one massive request, split work into smaller, focused tasks<\/li>\n<li>\n<strong>Monitor usage<\/strong>: Regularly check your API usage dashboard<\/li>\n<li>\n<strong>Set budgets<\/strong>: Configure spending limits with your LLM provider<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Advanced Configuration\n<\/h2>\n\n<h3>\n  \n  \n  Shared Configuration\n<\/h3>\n\n<p>Both Desktop and CLI share configuration stored at <code>~\/.config\/goose\/config.yaml<\/code>. You can manually edit this file for advanced customization:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>providers:\n  openai:\n    model: gpt-4o\n    api_key_env: OPENAI_API_KEY\n\nextensions:\n  computer_controller:\n    enabled: <span class=\"nb\">true\n    timeout<\/span>: 300\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Multiple Providers\n<\/h3>\n\n<p>goose supports multi-model configuration, letting you use different models for different tasks:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>goose configure\n<span class=\"c\"># Add multiple providers with different models<\/span>\n<span class=\"c\"># Switch between them as needed for your workflow<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Conclusion\n<\/h3>\n\n<p>goose on Windows has evolved into a robust, production-ready tool for developers. While there are Windows-specific considerations\u2014particularly around paths, permissions, and environment configuration\u2014the installation and setup process is straightforward. By following the best practices outlined in this guide, you'll be well-equipped to leverage goose's powerful AI-assisted development capabilities.<br>\nWhether you choose the Desktop application for its intuitive interface or the CLI for terminal integration, goose can dramatically accelerate your development workflow. Start with simple tasks, familiarize yourself with how goose operates, and gradually incorporate it into more complex aspects of your work.<br>\nThe key to success with goose is understanding it as a collaborative tool rather than a replacement for your expertise. Use it to handle repetitive tasks, explore unfamiliar technologies, and prototype quickly\u2014but always apply your judgment and review the results.<\/p>\n\n<h3>\n  \n  \n  Additional Resources\n<\/h3>\n\n<ul>\n<li><a href=\"https:\/\/block.github.io\/goose\/docs\/category\/getting-started\/\" rel=\"noopener noreferrer\">Official Documentation<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/block\/goose\" rel=\"noopener noreferrer\">GitHub Repository<\/a><\/li>\n<li><a href=\"https:\/\/discord.gg\/block-opensource\" rel=\"noopener noreferrer\">Community Discord<\/a><\/li>\n<li>Provider Documentation: Consult your LLM provider's docs for API specifics<\/li>\n<li><a href=\"https:\/\/github.com\/Lymah123\" rel=\"noopener noreferrer\">Follow me on my favorite space<\/a><\/li>\n<\/ul>\n\n<p><strong><em>Happy coding with goose!<\/em><\/strong><\/p>\n\n","category":["goose","ai","opensource","mcp"]},{"title":"Building a Tic-Tac-Toe Game with Rust, Bevy, and WebAssembly","pubDate":"Sun, 28 Sep 2025 12:55:14 +0000","link":"https:\/\/dev.to\/lymah\/building-a-tic-tac-toe-game-with-rust-bevy-and-webassembly-11l6","guid":"https:\/\/dev.to\/lymah\/building-a-tic-tac-toe-game-with-rust-bevy-and-webassembly-11l6","description":"<h2>\n  \n  \n  Introduction\n<\/h2>\n\n<p>I recently built a Tic-Tac-Toe game using Rust, the Bevy game engine, and WebAssembly. <br>\nThis project combines modern game development with artificial intelligence, running directly <br>\nin the browser thanks to WebAssembly. Let me walk you through how it works and what I learned.<\/p>\n<h2>\n  \n  \n  Technical Stack\n<\/h2>\n\n<ul>\n<li>\ud83e\udd80 Rust: Systems programming language<\/li>\n<li>\ud83c\udfae Bevy: Data-driven game engine<\/li>\n<li>\ud83e\udde0 Minimax AI: Advanced game algorithm<\/li>\n<li>\ud83c\udf10 WebAssembly: Browser-based deployment<\/li>\n<li>\ud83c\udfa8 HTML\/CSS: Responsive game interface<\/li>\n<\/ul>\n<h2>\n  \n  \n  Key Features\n<\/h2>\n\n<ol>\n<li>\n<p>Interactive Gameplay<\/p>\n\n<ul>\n<li>Click-to-play interface<\/li>\n<li>Real-time move validation<\/li>\n<li>Visual feedback with colored squares<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>AI Opponent<\/p>\n\n<ul>\n<li>Minimax algorithm implementation<\/li>\n<li>Alpha-beta pruning optimization<\/li>\n<li>Strategic decision making<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Modern Web Interface<\/p>\n\n<ul>\n<li>Responsive design<\/li>\n<li>Loading animations<\/li>\n<li>Clean, gradient-based UI<\/li>\n<li>Tech stack badges<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Game State Management<\/p>\n\n<ul>\n<li>Win detection<\/li>\n<li>Draw conditions<\/li>\n<li>Easy restart functionality<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h2>\n  \n  \n  Code Highlights\n<\/h2>\n<h3>\n  \n  \n  Gameboard Setup\n<\/h3>\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"c1\">\/\/ Key components of the board initialization<\/span>\n<span class=\"k\">pub<\/span> <span class=\"k\">struct<\/span> <span class=\"n\">BoardState<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">pub<\/span> <span class=\"n\">board<\/span><span class=\"p\">:<\/span> <span class=\"p\">[[<\/span><span class=\"nb\">Option<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">Player<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">;<\/span> <span class=\"mi\">3<\/span><span class=\"p\">];<\/span> <span class=\"mi\">3<\/span><span class=\"p\">],<\/span>\n    <span class=\"k\">pub<\/span> <span class=\"n\">current_player<\/span><span class=\"p\">:<\/span> <span class=\"n\">Player<\/span><span class=\"p\">,<\/span>\n    <span class=\"k\">pub<\/span> <span class=\"n\">game_over<\/span><span class=\"p\">:<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">,<\/span>\n    <span class=\"k\">pub<\/span> <span class=\"n\">winner<\/span><span class=\"p\">:<\/span> <span class=\"nb\">Option<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">Player<\/span><span class=\"o\">&gt;<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n<p><br>\nRust<\/p>\n<h3>\n  \n  \n  AI Implementation\n<\/h3>\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"c1\">\/\/ Minimax algorithm with alpha-beta pruning<\/span>\n<span class=\"k\">fn<\/span> <span class=\"nf\">minimax<\/span><span class=\"p\">(<\/span><span class=\"n\">board<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"p\">[[<\/span><span class=\"nb\">Option<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">Player<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">;<\/span> <span class=\"mi\">3<\/span><span class=\"p\">];<\/span> <span class=\"mi\">3<\/span><span class=\"p\">],<\/span> <span class=\"n\">depth<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"n\">maximizing<\/span><span class=\"p\">:<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"nb\">i32<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ ... algorithm implementation<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n<p><br>\nRust<\/p>\n<h2>\n  \n  \n  Learning Points\n<\/h2>\n\n<ol>\n<li>\n<p>Rust and ECS Architecture<\/p>\n\n<ul>\n<li>Component-based design<\/li>\n<li>System organization<\/li>\n<li>Resource management<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>WebAssembly Integration<\/p>\n\n<ul>\n<li>Rust-to-WASM compilation<\/li>\n<li>Browser performance optimization<\/li>\n<li>Web API interactions<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Game AI Development<\/p>\n\n<ul>\n<li>Minimax algorithm implementation<\/li>\n<li>Game tree traversal<\/li>\n<li>Performance optimization<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h2>\n  \n  \n  Deployment Process\n<\/h2>\n\n<ol>\n<li>\n<p>Build Process:<\/p>\n\n<ul>\n<li>Rust compilation to WASM<\/li>\n<li>Asset bundling<\/li>\n<li>CSS\/HTML optimization<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Hosting:<\/p>\n\n<ul>\n<li>Static file deployment<\/li>\n<li>WebAssembly loading<\/li>\n<li>Browser compatibility<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h2>\n  \n  \n  Docker Integration\n<\/h2>\n<h3>\n  \n  \n  Development Environment\n<\/h3>\n\n<p>One of the key aspects of this project is its containerized development environment using Docker. This ensures consistent builds across different platforms and simplifies the setup process for contributors.<\/p>\n<h2>\n  \n  \n  Docker Setup\n<\/h2>\n\n<p>The project uses a multi-stage Docker build process:<\/p>\n\n<ol>\n<li>Base development image with Rust toolchain<\/li>\n<li>WebAssembly compilation environment<\/li>\n<li>Production-ready web server<\/li>\n<\/ol>\n<h3>\n  \n  \n  Key Docker Components\n<\/h3>\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code>project\/\n\u251c\u2500\u2500 Dockerfile           # Main container configuration\n\u251c\u2500\u2500 docker-compose.yml   # Development orchestration\n\u2514\u2500\u2500 .dockerignore       # Build optimization rules\n<\/code><\/pre>\n\n<\/div>\n\n<h3>\n  \n  \n  Build Process\n<\/h3>\n\n<p>The Docker setup handles several crucial aspects:<\/p>\n\n<ol>\n<li>Development Environment<\/li>\n<\/ol>\n\n<ul>\n<li>Rust toolchain installation<\/li>\n<li>WASM target setup<\/li>\n<li>Development dependencies<\/li>\n<\/ul>\n\n<ol>\n<li>Build Tools<\/li>\n<\/ol>\n\n<ul>\n<li>trunk for asset bundling<\/li>\n<li>wasm-pack for WebAssembly compilation<\/li>\n<li>System libraries for Bevy<\/li>\n<\/ul>\n\n<ol>\n<li>Development Workflow<\/li>\n<\/ol>\n\n<ul>\n<li>Hot reloading support<\/li>\n<li>Volume mounting for live coding<\/li>\n<li>Port forwarding for local testing<\/li>\n<\/ul>\n<h2>\n  \n  \n  Running the Project\n<\/h2>\n\n<p><em>To start development:<\/em><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code><span class=\"gh\"># Build and start the development server<\/span>\ndocker-compose up --build\n\n<span class=\"gh\"># Access the game at http:\/\/localhost:8080<\/span>\n\n<span class=\"gh\"># Stop the server<\/span>\ndocker-compose down\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Benefits\n<\/h2>\n\n<ol>\n<li>Consistency<\/li>\n<\/ol>\n\n<ul>\n<li>Same environment for all developers<\/li>\n<li>Reproducible builds<\/li>\n<li>Simplified dependency management<\/li>\n<\/ul>\n\n<ol>\n<li>Cross-Platform<\/li>\n<\/ol>\n\n<ul>\n<li>Works on Windows, macOS, and Linux<\/li>\n<li>No local Rust installation required<\/li>\n<li>Consistent WebAssembly compilation<\/li>\n<\/ul>\n\n<ol>\n<li>Production Ready<\/li>\n<\/ol>\n\n<ul>\n<li>Optimized builds for deployment<\/li>\n<li>Small container footprint<\/li>\n<li>Easy cloud deployment<\/li>\n<\/ul>\n\n<blockquote>\n<p>This Docker integration makes the project more accessible to contributors and ensures reliable builds across different platforms and environments.<\/p>\n<\/blockquote>\n\n<h2>\n  \n  \n  Future Improvements\n<\/h2>\n\n<ol>\n<li>Multiplayer Support<\/li>\n<li>Difficulty Levels<\/li>\n<li>Move Animation<\/li>\n<li>Game History<\/li>\n<li>Score Tracking<\/li>\n<\/ol>\n\n<h2>\n  \n  \n  Repository Sections\n<\/h2>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight markdown\"><code>bevy-tic-tac-toe\/\n\u251c\u2500\u2500 src\/\n\u2502   \u251c\u2500\u2500 components\/\n\u2502   \u251c\u2500\u2500 systems\/\n\u2502   \u251c\u2500\u2500 resources\/\n\u2502   \u2514\u2500\u2500 main.rs\n\u251c\u2500\u2500 dist\/\n\u2502   \u2514\u2500\u2500 index.html\n\u251c\u2500\u2500 Cargo.toml\n\u2514\u2500\u2500 README.md\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Conclusion\n<\/h2>\n\n<p>This project demonstrates how modern web games can be built using Rust and WebAssembly, <br>\nproviding a smooth, native-like experience in the browser. The combination of Bevy's ECS <br>\narchitecture with Rust's safety guarantees made it possible to create a robust, <br>\nperformant game with minimal code.<\/p>\n\n","category":["rust","gamedev","bevy","webassembly"]},{"title":"\ud83e\udd80 Week 3 of Learning Rust: Match, Patterns, and the Power of Methods","pubDate":"Wed, 11 Jun 2025 03:35:56 +0000","link":"https:\/\/dev.to\/lymah\/week-3-of-learning-rust-match-patterns-and-the-power-of-methods-3ed4","guid":"https:\/\/dev.to\/lymah\/week-3-of-learning-rust-match-patterns-and-the-power-of-methods-3ed4","description":"<p>Welcome back to Week 3 of my Rust learning journey! Last week, I focused on structuring data with compound types and guiding program flow. This week felt like unlocking a new level. I dove into <strong>pattern matching<\/strong>, <code>match<\/code>\/<code>if let<\/code>, and how <strong>methods<\/strong> work in Rust (yes, Rust has methods!).<\/p>\n\n<p>Here's what I tackled:<\/p>\n\n<ul>\n<li>Pattern Matching:\n\n<ul>\n<li>\n<code>match<\/code> expressions<\/li>\n<li>\n<code>matches!<\/code> macro<\/li>\n<li>\n<code>if let<\/code> expressions<\/li>\n<li>Understanding various Patterns<\/li>\n<\/ul>\n\n\n<\/li>\n\n<li>Methods &amp; Associated Functions<\/li>\n\n<\/ul>\n\n<p>Let's dive into how these concepts are elevating my <em>Rust<\/em> code, and how my AI assistant is evolving into an even smarter partner in this learning process.<\/p>\n\n<h2>\n  \n  \n  1.  Pattern Matching\n<\/h2>\n\n<p>This was definitely the highlight of the week. Rust's pattern matching allows for incredibly concise and safe ways to handle different data variations, especially with <em>enums<\/em>. It feels so much more robust than chained <code>if\/else<\/code> statements.<\/p>\n\n<h3>\n  \n  \n  <code>match<\/code> Expressions\n<\/h3>\n\n<ul>\n<li>Rust\u2019s <code>match<\/code> is more powerful than what I\u2019ve used in other languages.<\/li>\n<li>You can match enums, primitives, structs, even nested patterns.<\/li>\n<\/ul>\n\n<p>Examples<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">match<\/span> <span class=\"n\">some_number<\/span> <span class=\"p\">{<\/span>\n      <span class=\"mi\">1<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"One!\"<\/span><span class=\"p\">),<\/span>\n      <span class=\"mi\">2<\/span> <span class=\"p\">|<\/span> <span class=\"mi\">3<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Two or three\"<\/span><span class=\"p\">),<\/span>\n      <span class=\"mi\">4<\/span><span class=\"o\">..=<\/span><span class=\"mi\">10<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Between four and ten\"<\/span><span class=\"p\">),<\/span>\n      <span class=\"n\">_<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Something else\"<\/span><span class=\"p\">),<\/span>\n  <span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">enum<\/span> <span class=\"n\">Coin<\/span> <span class=\"p\">{<\/span>\n    <span class=\"n\">Penny<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">Nickel<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">Dime<\/span><span class=\"p\">,<\/span>\n    <span class=\"nf\">Quarter<\/span><span class=\"p\">(<\/span><span class=\"n\">UsState<\/span><span class=\"p\">),<\/span> <span class=\"c1\">\/\/ Enum variant with associated data<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">enum<\/span> <span class=\"n\">UsState<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ For our Quarter example<\/span>\n    <span class=\"n\">Alabama<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">Alaska<\/span><span class=\"p\">,<\/span>\n    <span class=\"c1\">\/\/ ... many more states<\/span>\n    <span class=\"n\">California<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">value_in_cents<\/span><span class=\"p\">(<\/span><span class=\"n\">coin<\/span><span class=\"p\">:<\/span> <span class=\"n\">Coin<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"nb\">u8<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">coin<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"n\">Penny<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ Code block for Penny<\/span>\n            <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Lucky Penny!\"<\/span><span class=\"p\">);<\/span>\n            <span class=\"mi\">1<\/span>\n        <span class=\"p\">},<\/span>\n        <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"n\">Nickel<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"mi\">5<\/span><span class=\"p\">,<\/span>\n        <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"n\">Dime<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"mi\">10<\/span><span class=\"p\">,<\/span>\n        <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"nf\">Quarter<\/span><span class=\"p\">(<\/span><span class=\"n\">state<\/span><span class=\"p\">)<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ Destructure associated data<\/span>\n            <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"State quarter from {:?}!\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">state<\/span><span class=\"p\">);<\/span>\n            <span class=\"mi\">25<\/span>\n        <span class=\"p\">},<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Value of a Quarter: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"nf\">value_in_cents<\/span><span class=\"p\">(<\/span><span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"nf\">Quarter<\/span><span class=\"p\">(<\/span><span class=\"nn\">UsState<\/span><span class=\"p\">::<\/span><span class=\"n\">California<\/span><span class=\"p\">)));<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Value of a Penny: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"nf\">value_in_cents<\/span><span class=\"p\">(<\/span><span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"n\">Penny<\/span><span class=\"p\">));<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<blockquote>\n<p>I love how it enforces exhaustiveness. Rust forces you to think clearly.<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  <code>matches!<\/code>\n<\/h3>\n\n<p>The <em>matches!<\/em> macro is fantastic for a quick boolean check if a value matches a pattern, without extracting the value.<\/p>\n\n<p>Quick and clean way to check if a value matches a specific pattern<\/p>\n\n<p>Examples<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">if<\/span> <span class=\"nd\">matches!<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"nf\">Some<\/span><span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"It\u2019s Some!\"<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">coin<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"nf\">Quarter<\/span><span class=\"p\">(<\/span><span class=\"nn\">UsState<\/span><span class=\"p\">::<\/span><span class=\"n\">Alabama<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"nd\">matches!<\/span><span class=\"p\">(<\/span><span class=\"n\">coin<\/span><span class=\"p\">,<\/span> <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"nf\">Quarter<\/span><span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ Does coin match any Quarter variant?<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"It's definitely a quarter!\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"nd\">matches!<\/span><span class=\"p\">(<\/span><span class=\"n\">coin<\/span><span class=\"p\">,<\/span> <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"nf\">Quarter<\/span><span class=\"p\">(<\/span><span class=\"nn\">UsState<\/span><span class=\"p\">::<\/span><span class=\"n\">Alabama<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ Does it match a Quarter from Alabama?<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Specifically an Alabama Quarter!\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"o\">!<\/span><span class=\"nd\">matches!<\/span><span class=\"p\">(<\/span><span class=\"n\">coin<\/span><span class=\"p\">,<\/span> <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"n\">Penny<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Definitely not a penny.\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<blockquote>\n<p>I used this to simplify conditions that felt too heavy with <code>match<\/code>.<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  <code>if let<\/code>\n<\/h3>\n\n<p>When you only care about one specific variant of an enum or a single pattern, <code>if let<\/code> is a cleaner alternative to a full match expression.<br>\nGreat when you only care about one pattern.<\/p>\n\n<p>Examples<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">if<\/span> <span class=\"k\">let<\/span> <span class=\"nf\">Some<\/span><span class=\"p\">(<\/span><span class=\"n\">val<\/span><span class=\"p\">)<\/span> <span class=\"o\">=<\/span> <span class=\"n\">option<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Got a value: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">val<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">config_max<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">Some<\/span><span class=\"p\">(<\/span><span class=\"mi\">3u8<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"k\">let<\/span> <span class=\"nf\">Some<\/span><span class=\"p\">(<\/span><span class=\"n\">max<\/span><span class=\"p\">)<\/span> <span class=\"o\">=<\/span> <span class=\"n\">config_max<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ If config_max matches Some(max)<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The maximum is: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">max<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"No maximum configured.\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">let<\/span> <span class=\"n\">coin<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"n\">Dime<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ Using the Coin enum from above<\/span>\n    <span class=\"k\">if<\/span> <span class=\"k\">let<\/span> <span class=\"nn\">Coin<\/span><span class=\"p\">::<\/span><span class=\"nf\">Quarter<\/span><span class=\"p\">(<\/span><span class=\"n\">state<\/span><span class=\"p\">)<\/span> <span class=\"o\">=<\/span> <span class=\"n\">coin<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"It's a quarter from {:?}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">state<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"It's not a quarter.\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<blockquote>\n<p>Clean, but I learned it can hide unmatched variants, so I\u2019m using it carefully.<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  Patterns (The Building Blocks of Matching)\n<\/h3>\n\n<p>Understanding the various types of patterns is key to leveraging <code>match<\/code> and <code>if let<\/code>. I explored:<\/p>\n\n<ul>\n<li>\n<strong>Literals<\/strong>: <code>match x { 1 =&gt; ... }<\/code>\n<\/li>\n<li>\n<strong>Named Variables<\/strong>: <code>match x { some_var =&gt; ... }<\/code> (these bind the value)<\/li>\n<li>\n<strong>Wildcards<\/strong>: <code>match x { _ =&gt; ... }<\/code> (ignore the value)<\/li>\n<li>_ <strong>placeholder<\/strong>: For unused variables.<\/li>\n<li>\n<strong>Ranges<\/strong>: <code>match x { 1..=5 =&gt; ... }<\/code>\n<\/li>\n<li>\n<strong>Enums<\/strong>: <code>match coin { Coin::Penny =&gt; ... }<\/code>\n<\/li>\n<li>\n<strong>Structs<\/strong>: <code>match user { User { username, .. } =&gt; ... }<\/code> (destructuring!)<\/li>\n<li>\n<strong>Tuples<\/strong>: <code>match point { (x, y) =&gt; ... }<\/code> (destructuring!)<\/li>\n<li>\n<strong>References<\/strong>: <code>match &amp;value { &amp;10 =&gt; ... }<\/code> (matching on a reference)<\/li>\n<\/ul>\n\n<p><em>Learning to combine these patterns for complex scenarios is a journey, and the compiler is a great guide<\/em><\/p>\n\n<h2>\n  \n  \n  2. Methods &amp; Associated Functions\n<\/h2>\n\n<p>This was a very satisfying part of the week, as it allowed me to start making my custom <code>struct<\/code>s and <code>enum<\/code>s truly behave like \"objects\" (in a Rust sense, not OOP).<\/p>\n\n<h3>\n  \n  \n  Methods: <code>&amp;self<\/code>, <code>&amp;mut self<\/code>, <code>self<\/code>\n<\/h3>\n\n<p>Methods are functions defined on a struct or enum using an <code>impl<\/code> block, and they take <code>self<\/code> as their first parameter. The choice of <code>self<\/code> (<code>&amp;self<\/code>, <code>&amp;mut self<\/code>, <code>self<\/code>) dictates whether the method borrows immutably, borrows mutably, or takes ownership of the instance. This ties directly back to Week 1's ownership and borrowing rules!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">struct<\/span> <span class=\"n\">Rectangle<\/span> <span class=\"p\">{<\/span>\n    <span class=\"n\">width<\/span><span class=\"p\">:<\/span> <span class=\"nb\">u32<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">height<\/span><span class=\"p\">:<\/span> <span class=\"nb\">u32<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">impl<\/span> <span class=\"n\">Rectangle<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ Method that immutably borrows `self`<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"nf\">area<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"k\">self<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"nb\">u32<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">self<\/span><span class=\"py\">.width<\/span> <span class=\"o\">*<\/span> <span class=\"k\">self<\/span><span class=\"py\">.height<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ Method that mutably borrows `self`<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"nf\">set_width<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"k\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">new_width<\/span><span class=\"p\">:<\/span> <span class=\"nb\">u32<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">self<\/span><span class=\"py\">.width<\/span> <span class=\"o\">=<\/span> <span class=\"n\">new_width<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ Method that takes ownership of `self`<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"nf\">consume_and_describe<\/span><span class=\"p\">(<\/span><span class=\"k\">self<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Consuming a rectangle of {}x{}\"<\/span><span class=\"p\">,<\/span> <span class=\"k\">self<\/span><span class=\"py\">.width<\/span><span class=\"p\">,<\/span> <span class=\"k\">self<\/span><span class=\"py\">.height<\/span><span class=\"p\">);<\/span>\n        <span class=\"c1\">\/\/ `self` is dropped here, so you can't use it afterwards<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">rect1<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Rectangle<\/span> <span class=\"p\">{<\/span> <span class=\"n\">width<\/span><span class=\"p\">:<\/span> <span class=\"mi\">30<\/span><span class=\"p\">,<\/span> <span class=\"n\">height<\/span><span class=\"p\">:<\/span> <span class=\"mi\">50<\/span> <span class=\"p\">};<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Initial area: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">rect1<\/span><span class=\"nf\">.area<\/span><span class=\"p\">());<\/span> <span class=\"c1\">\/\/ Calling an immutable method<\/span>\n\n    <span class=\"n\">rect1<\/span><span class=\"nf\">.set_width<\/span><span class=\"p\">(<\/span><span class=\"mi\">40<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ Calling a mutable method<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"New width: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">rect1<\/span><span class=\"py\">.width<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"n\">rect1<\/span><span class=\"nf\">.consume_and_describe<\/span><span class=\"p\">();<\/span> <span class=\"c1\">\/\/ This consumes rect1<\/span>\n    <span class=\"c1\">\/\/ println!(\"Can't use rect1 after consumption: {}\", rect1.width); \/\/ Error!<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Associated Functions\n<\/h3>\n\n<p>Associated functions are also defined in <code>impl<\/code> blocks, but they <em>don't<\/em> take <code>self<\/code> as their first parameter. They're often used as constructors or utility functions related to the type, similar to static methods in other languages.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">impl<\/span> <span class=\"n\">Rectangle<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ Associated function (constructor)<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"nf\">square<\/span><span class=\"p\">(<\/span><span class=\"n\">size<\/span><span class=\"p\">:<\/span> <span class=\"nb\">u32<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"n\">Rectangle<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">Rectangle<\/span> <span class=\"p\">{<\/span> <span class=\"n\">width<\/span><span class=\"p\">:<\/span> <span class=\"n\">size<\/span><span class=\"p\">,<\/span> <span class=\"n\">height<\/span><span class=\"p\">:<\/span> <span class=\"n\">size<\/span> <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">sq<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">Rectangle<\/span><span class=\"p\">::<\/span><span class=\"nf\">square<\/span><span class=\"p\">(<\/span><span class=\"mi\">25<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ Calling an associated function<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Square area: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">sq<\/span><span class=\"nf\">.area<\/span><span class=\"p\">());<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  <em><strong>My AI Assistant Insight:<\/strong><\/em> When I needed to remember the exact syntax for defining a method vs. an associated function, or the difference between <code>&amp;self<\/code>, <code>&amp;mut self<\/code>, and <code>self<\/code>, a quick prompt like <code>\"Rust method with mutable self vs immutable self\"<\/code> immediately gave me the right examples and explanations. It\u2019s like having the Rust docs indexed for my specific questions.\n<\/h3>\n\n<h2>\n  \n  \n  Learning by Doing: More Rust by Example Immersion\n<\/h2>\n\n<p>My primary learning tool continues to be Rust by example (<a href=\"https:\/\/doc.rust-lang.org\/rust-by-example\/\" rel=\"noopener noreferrer\">https:\/\/doc.rust-lang.org\/rust-by-example\/<\/a>). I diligently worked through all the exercises and examples in the \"Pattern Matching,\" \"Methods,\" and \"Associated Functions\" sections this week.<\/p>\n\n<p>This hands-on practice was absolutely critical for internalizing these concepts:<\/p>\n\n<ul>\n<li>\n<strong>Encountering Match Exhaustiveness<\/strong>: The compiler quickly reminded me if I missed a case in a <code>match<\/code> expression, which was a great learning experience.<\/li>\n<li>\n<strong>Borrowing Rules with Methods<\/strong>: Practicing methods that take <code>&amp;self<\/code> and <code>&amp;mut self<\/code> really solidified my understanding of ownership and borrowing from Week 1.<\/li>\n<li>\n<strong>Syntax Muscle Memory<\/strong>: Repeatedly writing <code>impl<\/code> blocks and various patterns helped build muscle memory for Rust's syntax.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Week 3 Reflections\n<\/h2>\n\n<p>This week was incredibly satisfying. Pattern matching is a powerful paradigm that makes Rust code both safer (due to exhaustiveness checks) and more readable. Defining methods and associated functions brought a new level of organization and functionality to my custom data types. The interplay between these new concepts and the core ownership\/borrowing rules from Week 1 is becoming clearer.<\/p>\n\n<p>My AI assistant is now less about \"what does this keyword do?\" and more about \"how can I apply this concept idiomatically?\" or \"show me a more advanced example of this pattern.\" It's accelerating my understanding of best practices and complex syntax, allowing me to explore more deeply than I might on my own.<\/p>\n\n<p><em>What's your favorite use case for match expressions, or a powerful method you've written in Rust? Share your insights below!<\/em><\/p>\n\n","category":["rust","beginners","buildinpublic","ai"]},{"title":"Week 2 of Learning Rust: Tuples, Enums & Control Flow","pubDate":"Mon, 02 Jun 2025 00:55:06 +0000","link":"https:\/\/dev.to\/lymah\/week-2-of-learning-rust-tuples-enums-control-flow-4m2c","guid":"https:\/\/dev.to\/lymah\/week-2-of-learning-rust-tuples-enums-control-flow-4m2c","description":"<p>Hello, fellow Rustaceans (or aspiring ones)!Welcome back to <strong>Week 2<\/strong> of my deep dive into the Rust programming language, and this week I explored <strong>compound types<\/strong> and <strong>control flow<\/strong>. Here's what I learned, where I got stuck, and how I'm making it make sense.<\/p>\n\n<p>Here's what I tackled:<\/p>\n\n<p><strong>- A. Compound Types:<\/strong><\/p>\n\n<ul>\n<li>\n<code>String<\/code> (and its relationship with <code>&amp;str<\/code>)<\/li>\n<li>Arrays<\/li>\n<li>Slices<\/li>\n<li>Tuples<\/li>\n<li>Structs<\/li>\n<li>Enums<\/li>\n<\/ul>\n\n<p><strong>- B. Control Flow:<\/strong><\/p>\n\n<ul>\n<li><code>if\/else if\/else<\/code><\/li>\n<li><code>loop<\/code><\/li>\n<li><code>while<\/code><\/li>\n<li>\n<code>for<\/code> loops with iterators<\/li>\n<\/ul>\n\n<p>Let's dive into how these building blocks are starting to click for me, and how AI is continuing to be a valuable co-pilot.<\/p>\n\n\n\n\n<h3>\n  \n  \n  A. Compound Types\n<\/h3>\n\n<p>Last week, we dealt with simple numbers and booleans. This week was all about grouping related data and defining my own custom types.<\/p>\n\n<h4>\n  \n  \n  1. <code>String<\/code> vs. <code>&amp;str<\/code>\n<\/h4>\n\n<p>This was probably the most nuanced part of learning about text.<\/p>\n\n<p><strong>- <code>String<\/code><\/strong>: Owned, mutable, grows on the heap. Think of it as a dynamic, editable document.<\/p>\n\n<p><strong>- <code>&amp;str<\/code> (string slice):<\/strong><br>\n An immutable reference to a <code>String<\/code>(or a string literal that lives in the binary). Think of it as a view or a borrow of part of a document.<\/p>\n\n<p>Understanding when to use which and how they interact is fundamental for efficient and safe <code>string<\/code> manipulation in Rust.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">s1<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">String<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Hello\"<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ Owned, mutable String<\/span>\n    <span class=\"n\">s1<\/span><span class=\"nf\">.push_str<\/span><span class=\"p\">(<\/span><span class=\"s\">\", world!\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"{}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">s1<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">let<\/span> <span class=\"n\">s_slice<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"o\">&amp;<\/span><span class=\"n\">s1<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"o\">..<\/span><span class=\"mi\">5<\/span><span class=\"p\">];<\/span> <span class=\"c1\">\/\/ Immutable slice from s1<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Slice: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">s_slice<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">let<\/span> <span class=\"n\">literal_slice<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"This is a literal\"<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ String literal is also &amp;str<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Literal: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">literal_slice<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ AI helped clarify conversion:<\/span>\n    <span class=\"c1\">\/\/ Prompt: \"How do I convert &amp;str to String in Rust?\"<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">from_slice<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">String<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">(<\/span><span class=\"n\">literal_slice<\/span><span class=\"p\">);<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Converted to String: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">from_slice<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><em>My AI Assistant Insight: I found myself frequently asking my AI assistant for clarification on <code>String vs. &amp;str<\/code> scenarios. It quickly provided examples for conversions <code>(.to_string(), String::from())<\/code> and explained the performance implications of each, helping me choose the right type for the job.<\/em><\/p>\n\n<h4>\n  \n  \n  2. Arrays and Slices: Fixed vs. Dynamic Collections\n<\/h4>\n\n<ul>\n<li>\n<strong>Arrays<\/strong>: Fixed-size collections of elements of the same type, allocated on the stack. Great for compile-time known sizes.\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code>\n<span class=\"k\">let<\/span> <span class=\"n\">arr<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nb\">i32<\/span><span class=\"p\">;<\/span> <span class=\"mi\">5<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">4<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">];<\/span>\n<span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"First element: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">arr<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]);<\/span>\n<span class=\"c1\">\/\/ arr[5] would cause a panic at runtime!<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<ul>\n<li>\n<strong>Slices<\/strong>: A dynamic view into a part of a collection (like an array or <code>Vec<\/code>). They don't take ownership and are essentially a pointer to the start and a length.\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">let<\/span> <span class=\"n\">a<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">4<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">];<\/span>\n<span class=\"k\">let<\/span> <span class=\"n\">slice<\/span> <span class=\"o\">=<\/span> <span class=\"o\">&amp;<\/span><span class=\"n\">a<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"o\">..<\/span><span class=\"mi\">4<\/span><span class=\"p\">];<\/span> <span class=\"c1\">\/\/ slice is &amp;[2, 3, 4]<\/span>\n<span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Slice: {:?}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">slice<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ Needs Debug trait for printing arrays\/slices<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Slices are incredibly powerful for passing parts of collections around efficiently without copying.<\/p>\n\n<h4>\n  \n  \n  3. Tuples: Grouping Different Types Together\n<\/h4>\n\n<p>Tuples are simple, fixed-size collections that can hold values of <em>different<\/em> types. Useful for returning multiple values from a function.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">get_user_info<\/span><span class=\"p\">()<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"p\">(<\/span><span class=\"s\">\"Alice\"<\/span><span class=\"p\">,<\/span> <span class=\"mi\">30<\/span><span class=\"p\">,<\/span> <span class=\"k\">true<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">person<\/span><span class=\"p\">:<\/span> <span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">)<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"s\">\"Bob\"<\/span><span class=\"p\">,<\/span> <span class=\"mi\">25<\/span><span class=\"p\">,<\/span> <span class=\"k\">false<\/span><span class=\"p\">);<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Name: {}, Age: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">person<\/span><span class=\"na\">.0<\/span><span class=\"p\">,<\/span> <span class=\"n\">person<\/span><span class=\"na\">.1<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ Access by index<\/span>\n\n    <span class=\"k\">let<\/span> <span class=\"p\">(<\/span><span class=\"n\">name<\/span><span class=\"p\">,<\/span> <span class=\"n\">age<\/span><span class=\"p\">,<\/span> <span class=\"n\">_is_active<\/span><span class=\"p\">)<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">get_user_info<\/span><span class=\"p\">();<\/span> <span class=\"c1\">\/\/ Destructuring<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"User from function: {}, {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">,<\/span> <span class=\"n\">age<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  4. Structs\n<\/h4>\n\n<p>Structs are like classes in other languages (without methods, initially), they let you create custom data types with named fields. This is fundamental for organizing related data.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">struct<\/span> <span class=\"n\">User<\/span> <span class=\"p\">{<\/span>\n    <span class=\"n\">username<\/span><span class=\"p\">:<\/span> <span class=\"nb\">String<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">email<\/span><span class=\"p\">:<\/span> <span class=\"nb\">String<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">sign_in_count<\/span><span class=\"p\">:<\/span> <span class=\"nb\">u64<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">active<\/span><span class=\"p\">:<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">user1<\/span> <span class=\"o\">=<\/span> <span class=\"n\">User<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">username<\/span><span class=\"p\">:<\/span> <span class=\"nn\">String<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">(<\/span><span class=\"s\">\"alice123\"<\/span><span class=\"p\">),<\/span>\n        <span class=\"n\">email<\/span><span class=\"p\">:<\/span> <span class=\"nn\">String<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">(<\/span><span class=\"s\">\"alice@example.com\"<\/span><span class=\"p\">),<\/span>\n        <span class=\"n\">active<\/span><span class=\"p\">:<\/span> <span class=\"k\">true<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">sign_in_count<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span>\n    <span class=\"p\">};<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"User: {}, Email: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">user1<\/span><span class=\"py\">.username<\/span><span class=\"p\">,<\/span> <span class=\"n\">user1<\/span><span class=\"py\">.email<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ AI's help with update syntax:<\/span>\n    <span class=\"c1\">\/\/ Prompt: \"How do I create a new struct instance from an existing one in Rust?\"<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">user2<\/span> <span class=\"o\">=<\/span> <span class=\"n\">User<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">email<\/span><span class=\"p\">:<\/span> <span class=\"nn\">String<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">(<\/span><span class=\"s\">\"bob@example.com\"<\/span><span class=\"p\">),<\/span>\n        <span class=\"o\">..<\/span><span class=\"n\">user1<\/span> <span class=\"c1\">\/\/ Fills in remaining fields from user1<\/span>\n    <span class=\"p\">};<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"User2: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">user2<\/span><span class=\"py\">.username<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ User2's username is also alice123<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  5. Enums\n<\/h4>\n\n<p><code>Enums<\/code> are fantastic for representing a set of distinct, related possibilities. Coupled with the match control flow, they become incredibly powerful for handling different states or data variations.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">enum<\/span> <span class=\"n\">Message<\/span> <span class=\"p\">{<\/span>\n    <span class=\"n\">Quit<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">Move<\/span> <span class=\"p\">{<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span> <span class=\"p\">},<\/span> <span class=\"c1\">\/\/ Enum variant with anonymous struct<\/span>\n    <span class=\"nf\">Write<\/span><span class=\"p\">(<\/span><span class=\"nb\">String<\/span><span class=\"p\">),<\/span> <span class=\"c1\">\/\/ Enum variant with a String<\/span>\n    <span class=\"nf\">ChangeColor<\/span><span class=\"p\">(<\/span><span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">),<\/span> <span class=\"c1\">\/\/ Enum variant with a tuple<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">process_message<\/span><span class=\"p\">(<\/span><span class=\"n\">msg<\/span><span class=\"p\">:<\/span> <span class=\"n\">Message<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">msg<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nn\">Message<\/span><span class=\"p\">::<\/span><span class=\"n\">Quit<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The Quit message was received.\"<\/span><span class=\"p\">),<\/span>\n        <span class=\"nn\">Message<\/span><span class=\"p\">::<\/span><span class=\"n\">Move<\/span> <span class=\"p\">{<\/span> <span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span> <span class=\"p\">}<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Move to {} {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"p\">),<\/span>\n        <span class=\"nn\">Message<\/span><span class=\"p\">::<\/span><span class=\"nf\">Write<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">)<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Text message: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">text<\/span><span class=\"p\">),<\/span>\n        <span class=\"nn\">Message<\/span><span class=\"p\">::<\/span><span class=\"nf\">ChangeColor<\/span><span class=\"p\">(<\/span><span class=\"n\">r<\/span><span class=\"p\">,<\/span> <span class=\"n\">g<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Change color to R:{} G:{} B:{}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">r<\/span><span class=\"p\">,<\/span> <span class=\"n\">g<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">m1<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">Message<\/span><span class=\"p\">::<\/span><span class=\"n\">Quit<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">m2<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">Message<\/span><span class=\"p\">::<\/span><span class=\"n\">Move<\/span> <span class=\"p\">{<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"p\">:<\/span> <span class=\"mi\">20<\/span> <span class=\"p\">};<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">m3<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">Message<\/span><span class=\"p\">::<\/span><span class=\"nf\">Write<\/span><span class=\"p\">(<\/span><span class=\"nn\">String<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">(<\/span><span class=\"s\">\"hello Rust\"<\/span><span class=\"p\">));<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">m4<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">Message<\/span><span class=\"p\">::<\/span><span class=\"nf\">ChangeColor<\/span><span class=\"p\">(<\/span><span class=\"mi\">255<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">100<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"nf\">process_message<\/span><span class=\"p\">(<\/span><span class=\"n\">m1<\/span><span class=\"p\">);<\/span>\n    <span class=\"nf\">process_message<\/span><span class=\"p\">(<\/span><span class=\"n\">m2<\/span><span class=\"p\">);<\/span>\n    <span class=\"nf\">process_message<\/span><span class=\"p\">(<\/span><span class=\"n\">m3<\/span><span class=\"p\">);<\/span>\n    <span class=\"nf\">process_message<\/span><span class=\"p\">(<\/span><span class=\"n\">m4<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  B. Control Flow\n<\/h3>\n\n<p>After defining my data, the next step was to control what my program does and when. Rust's control flow constructs are powerful and familiar, but with some Rust-specific nuances.<\/p>\n\n<h4>\n  \n  \n  1. <code>if\/else if\/else<\/code>: Conditional Execution\n<\/h4>\n\n<p>Pretty standard, but remember that <code>if<\/code> conditions <em>must<\/em> evaluate to a <code>bool<\/code>. Also, <code>if<\/code> is an expression, which is a neat feature for assigning values conditionally.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">number<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">7<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"n\">number<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">5<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"condition was true\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"condition was false\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">let<\/span> <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"k\">if<\/span> <span class=\"n\">number<\/span> <span class=\"o\">%<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">{<\/span> <span class=\"s\">\"even\"<\/span> <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span> <span class=\"s\">\"odd\"<\/span> <span class=\"p\">};<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The number is {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">result<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  2. <code>loop<\/code>: Infinite Loops (with <code>break<\/code> and <code>continue<\/code>)\n<\/h4>\n\n<p>The <code>loop<\/code> keyword creates an infinite loop, perfect for retrying operations or listening for events. <code>break<\/code> exits, <code>continue<\/code> skips to the next iteration. You can even return values from a <code>loop<\/code>.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">counter<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"k\">loop<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">counter<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">1<\/span><span class=\"p\">;<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">counter<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">10<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">break<\/span> <span class=\"n\">counter<\/span> <span class=\"o\">*<\/span> <span class=\"mi\">2<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ Returns a value from the loop!<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">};<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The result is {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">result<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ result will be 20<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  3. <code>while<\/code>: Conditional Loops\n<\/h4>\n\n<p>For loops that run as long as a condition is true.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">number<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">3<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">while<\/span> <span class=\"n\">number<\/span> <span class=\"o\">!=<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"{}!\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">number<\/span><span class=\"p\">);<\/span>\n        <span class=\"n\">number<\/span> <span class=\"o\">-=<\/span> <span class=\"mi\">1<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"LIFTOFF!!!\"<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  5. <code>for<\/code> Loops\n<\/h4>\n\n<p><code>for<\/code> loops Iterates Over Collections. This is the most common loop for iterating over collections. Rust's for loop works with iterators, which is a very efficient and safe way to process data.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">a<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">20<\/span><span class=\"p\">,<\/span> <span class=\"mi\">30<\/span><span class=\"p\">,<\/span> <span class=\"mi\">40<\/span><span class=\"p\">,<\/span> <span class=\"mi\">50<\/span><span class=\"p\">];<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">element<\/span> <span class=\"k\">in<\/span> <span class=\"n\">a<\/span><span class=\"nf\">.iter<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ Iterate over array elements<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The value is: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">element<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ Looping with a range<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">number<\/span> <span class=\"k\">in<\/span> <span class=\"mi\">1<\/span><span class=\"o\">..<\/span><span class=\"mi\">4<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ Range is exclusive of the end (1, 2, 3)<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"{}!\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">number<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ AI helped with reverse iteration:<\/span>\n    <span class=\"c1\">\/\/ Prompt: \"How do I loop backwards over a range in Rust?\"<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">number<\/span> <span class=\"k\">in<\/span> <span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"o\">..<\/span><span class=\"mi\">4<\/span><span class=\"p\">)<\/span><span class=\"nf\">.rev<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ Reverse range<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"{}!\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">number<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Week 2 Reflections\n<\/h2>\n\n<p>This week felt like I gained a lot of power in organizing and controlling my programs. Understanding <code>String<\/code> vs. <code>&amp;str<\/code> and the different compound types like <code>struct<\/code> and <code>enum<\/code> is crucial for writing robust Rust. The control flow structures felt familiar from other languages, but seeing them used as expressions (like <code>if<\/code> statements) was a neat Rust-specific twist.<\/p>\n\n<p>My AI assistant continues to be a fantastic resource for quick syntax lookups, clarifying nuances (especially with <code>String<\/code> vs. <code>&amp;str<\/code>), and discovering idiomatic ways to do things (like <code>.rev()<\/code> on iterators). It's accelerating my learning without doing the thinking for me, which is exactly the balance I'm aiming for in 2025.<\/p>\n\n<p>In case you missed <a href=\"https:\/\/dev.to\/lymah\/week-1-of-learning-rust-ownership-broke-my-brain-and-thats-okay-6aa\">week 1<\/a>, check it out here. <\/p>\n\n<p>See y'all in week 3.<\/p>\n\n","category":["rust","beginners","programming","softwaredevelopment"]},{"title":"\ud83e\udd80 Week 1 of Learning Rust: Ownership Broke My Brain (and That\u2019s Okay)","pubDate":"Sun, 25 May 2025 22:26:15 +0000","link":"https:\/\/dev.to\/lymah\/week-1-of-learning-rust-ownership-broke-my-brain-and-thats-okay-6aa","guid":"https:\/\/dev.to\/lymah\/week-1-of-learning-rust-ownership-broke-my-brain-and-thats-okay-6aa","description":"<p>Hey everyone! \ud83d\udc4b<br><br>\nI just wrapped up <strong>Week 1<\/strong> of my journey to learn fundamental of the <strong>Rust programming language<\/strong> from scratch and it\u2019s been a ride and documented weekly right here on Dev.to. My goal is to not just learn the language, but to openly share my struggles, breakthroughs, and how I'm leveraging the power of AI in this journey in 2025.<\/p>\n\n<p>Here\u2019s what I learned, what confused me, how I got unstuck, and what I\u2019m building next. Without further ado, let's unpack what I learned and how I'm navigating Rust's unique challenges.<\/p>\n<h3>\n  \n  \n  1. Variables\n<\/h3>\n\n<p>Coming from Python, variables in Rust felt familiar at first, but with a crucial twist: immutability by default. This was the first hint of Rust's philosophy: safety and predictability.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code>\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">x<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">5<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ Immutable by default<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The value of x is: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ x = 6; \/\/ This would cause a compile-time error!<\/span>\n    <span class=\"c1\">\/\/ println!(\"The value of x is: {}\", x);<\/span>\n\n    <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">10<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ Explicitly mutable<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The value of y is: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"p\">);<\/span>\n    <span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">12<\/span><span class=\"p\">;<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The new value of y is: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ Shadowing is cool too!<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">z<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"hello\"<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">z<\/span> <span class=\"o\">=<\/span> <span class=\"n\">z<\/span><span class=\"nf\">.len<\/span><span class=\"p\">();<\/span> <span class=\"c1\">\/\/ z is now 5<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The value of z is: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">z<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The <code>mut<\/code> keyword is a constant reminder of Rust's safety guarantees. No accidental modifications here! And <code>shadowing<\/code>, that's a neat way to reuse variable names with a new value and type.<\/p>\n\n<h3>\n  \n  \n  2. Basic Types (Numbers, Chars, Bools, Unit)\n<\/h3>\n\n<p>Rust's strong typing was another significant shift. Explicitly defining integer sizes (<code>i32<\/code>, <code>u64<\/code>), understanding floating-point types (<code>f32<\/code>, <code>f64<\/code>), and working with <code>char<\/code> and <code>bool<\/code> felt very robust.<\/p>\n\n<p>The <code>()<\/code> unit type, which signifies \"no value,\" is also a simple but powerful concept, especially when thinking about functions that don't return anything.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ Numbers<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">int_32<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">42<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">float_64<\/span><span class=\"p\">:<\/span> <span class=\"nb\">f64<\/span> <span class=\"o\">=<\/span> <span class=\"mf\">3.14<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"c1\">\/\/ Char, Bool, Unit<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">single_char<\/span><span class=\"p\">:<\/span> <span class=\"nb\">char<\/span> <span class=\"o\">=<\/span> <span class=\"sc\">'R'<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">is_learning<\/span><span class=\"p\">:<\/span> <span class=\"nb\">bool<\/span> <span class=\"o\">=<\/span> <span class=\"k\">true<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">unit_value<\/span> <span class=\"o\">=<\/span> <span class=\"p\">();<\/span> <span class=\"c1\">\/\/ This is the unit type<\/span>\n\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Int: {}, Float: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">int_32<\/span><span class=\"p\">,<\/span> <span class=\"n\">float_64<\/span><span class=\"p\">);<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Char: {}, Bool: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">single_char<\/span><span class=\"p\">,<\/span> <span class=\"n\">is_learning<\/span><span class=\"p\">);<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Unit value: {:?}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">unit_value<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ Need Debug trait to print unit<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Statements vs. Expressions\n<\/h3>\n\n<p>This was a concept I'd encountered before, but Rust truly hammers it home. <strong>Statements<\/strong> perform actions but don't return values (e.g., variable declarations). <strong>Expressions<\/strong> evaluate to a value (e.g., a function call, a block of code). This makes <code>if<\/code>blocks or even entire function bodies act as expressions, which is super powerful!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code>\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">6<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ This is a statement<\/span>\n\n    <span class=\"k\">let<\/span> <span class=\"n\">x<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ This entire block is an expression<\/span>\n        <span class=\"k\">let<\/span> <span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">3<\/span><span class=\"p\">;<\/span>\n        <span class=\"n\">y<\/span> <span class=\"o\">+<\/span> <span class=\"mi\">1<\/span> <span class=\"c1\">\/\/ No semicolon means it's an expression<\/span>\n    <span class=\"p\">};<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The value of x is: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ x will be 4<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  3.  Functions\n<\/h3>\n\n<p>Functions in Rust are quite straightforward, with explicit type annotations for parameters and return values. This compile-time check helps catch errors early.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code>\n<span class=\"k\">fn<\/span> <span class=\"nf\">add_numbers<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"nb\">i32<\/span> <span class=\"p\">{<\/span>\n    <span class=\"n\">x<\/span> <span class=\"o\">+<\/span> <span class=\"n\">y<\/span> <span class=\"c1\">\/\/ This is an expression, equivalent to `return x + y;`<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">greet<\/span><span class=\"p\">(<\/span><span class=\"n\">name<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ No return value, implicitly returns unit ()<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Hello, {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">sum<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">add_numbers<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">,<\/span> <span class=\"mi\">7<\/span><span class=\"p\">);<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The sum is: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">sum<\/span><span class=\"p\">);<\/span>\n    <span class=\"nf\">greet<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Rustacean\"<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  4. Ownership: My First Rust \"Aha!\" (and Head-Scratcher) Moment\n<\/h3>\n\n<p>This is where Rust truly differentiates itself, and honestly, where I spent the bulk of my time this week. Ownership is Rust's core concept for memory safety without a garbage collector. It dictates how data is managed in memory.<\/p>\n\n<p><em><strong>The three rules of ownership:<\/strong><\/em><\/p>\n\n<ol>\n<li>Each value in Rust has a variable that's called its owner.<\/li>\n<li>There can only be one owner at a time.<\/li>\n<li>When the owner goes out of scope, the value will be dropped.<\/li>\n<\/ol>\n\n<p>Initially, this felt very restrictive, especially when working with <code>String<\/code>s. The concept of \"moves\" where ownership is transferred, rather than data being copied, was fascinating and challenging.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code>\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">s1<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">String<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">(<\/span><span class=\"s\">\"hello\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">s2<\/span> <span class=\"o\">=<\/span> <span class=\"n\">s1<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ s1 is MOVED to s2, s1 is no longer valid!<\/span>\n\n    <span class=\"c1\">\/\/ println!(\"s1: {}\", s1); \/\/ This would cause a compile-time error!<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"s2: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">s2<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">let<\/span> <span class=\"n\">s3<\/span> <span class=\"o\">=<\/span> <span class=\"n\">s2<\/span><span class=\"nf\">.clone<\/span><span class=\"p\">();<\/span> <span class=\"c1\">\/\/ Deep copy, both s2 and s3 are valid<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"s2: {}, s3: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">s2<\/span><span class=\"p\">,<\/span> <span class=\"n\">s3<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  My AI-Assisted Ownership Breakdown\n<\/h3>\n\n<p>When I first hit this, my brain twisted. I turned to my AI coding assistant using GitHub Copilot Chat.<\/p>\n\n<p><strong><em>My Prompt<\/em><\/strong><\/p>\n\n<blockquote>\n<p>Explain Rust ownership (moves, drops, scope) to me as simply as possible, using an analogy from daily life, and then provide a simple code example that demonstrates a move.<\/p>\n<\/blockquote>\n\n<p><em><strong>AI's Analogy (Paraphrased)<\/strong><\/em><\/p>\n\n<p>Think of a library book. Only one person can check out a book at a time (one owner). When you return the book (owner goes out of scope), it's available again (dropped). If you lend your book to someone else, you no longer have it (moved).<\/p>\n\n<p>This analogy, combined with the AI-generated code example, really helped solidify the concept for me. It wasn't perfect, but it gave me a strong starting point to then dive deeper into \"The Book.\"<\/p>\n\n<h3>\n  \n  \n  5.  References and Borrowing\n<\/h3>\n\n<p>If ownership defines who has the data, references and borrowing are how you temporarily access that data without taking ownership. This is crucial for passing data to functions without having to copy it or lose ownership.<\/p>\n\n<p><strong><em>The key rules of borrowing:<\/em><\/strong><\/p>\n\n<ul>\n<li>At any given time, you can have either one mutable reference or any number of immutable references.<\/li>\n<li>References must always be valid.<\/li>\n<\/ul>\n\n<p>This \"one mutable OR many immutable\" rule is Rust's magic for preventing data races at compile time. It's strict, but it makes the code incredibly safe.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code>\n<span class=\"k\">fn<\/span> <span class=\"nf\">calculate_length<\/span><span class=\"p\">(<\/span><span class=\"n\">s<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">String<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"nb\">usize<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ Takes a reference<\/span>\n    <span class=\"n\">s<\/span><span class=\"nf\">.len<\/span><span class=\"p\">()<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">change_string<\/span><span class=\"p\">(<\/span><span class=\"n\">some_string<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"nb\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ Takes a mutable reference<\/span>\n    <span class=\"n\">some_string<\/span><span class=\"nf\">.push_str<\/span><span class=\"p\">(<\/span><span class=\"s\">\", world!\"<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">s1<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">String<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">(<\/span><span class=\"s\">\"hello\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">len<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">calculate_length<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">s1<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ Pass a reference<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The length of '{}' is {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">s1<\/span><span class=\"p\">,<\/span> <span class=\"n\">len<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ s1 is still valid!<\/span>\n\n    <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">s2<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">String<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">(<\/span><span class=\"s\">\"hello\"<\/span><span class=\"p\">);<\/span>\n    <span class=\"nf\">change_string<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"n\">s2<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ Pass a mutable reference<\/span>\n    <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"The modified string is: {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">s2<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ This would cause a compile-time error:<\/span>\n    <span class=\"c1\">\/\/ let r1 = &amp;mut s2;<\/span>\n    <span class=\"c1\">\/\/ let r2 = &amp;mut s2; \/\/ Cannot have two mutable references at once!<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Understanding of Memory(Heap vs. Stack)\n<\/h3>\n\n<p>A big piece that helped me grasp ownership was understanding where data lives in memory.<\/p>\n\n<p><strong>- Stack:<\/strong> This is where fixed-size data lives, and it's fast! Things like integers, booleans, and fixed-size arrays go here. Data is pushed and popped in a strict order.<br>\n  <strong>- Heap<\/strong>: This is for data whose size isn't known at compile time, or that might change. <code>String<\/code> is a great example, its text content lives on the heap, while the <code>String<\/code> struct itself (pointer, length, capacity) lives on the stack. Accessing heap data is slower because you have to follow a pointer.<\/p>\n\n<p>This distinction is crucial for ownership. When you move a <code>String<\/code>, you're effectively moving the <em>ownership<\/em> of the data on the <em>heap<\/em>, not necessarily copying the actual large data. This prevents multiple pointers to the same heap data, eliminating common memory bugs like double-free errors.<\/p>\n\n<h2>\n  \n  \n  Learning by Doing: Rust by Pactice\n<\/h2>\n\n<p>eyond just reading, I spent a good amount of time working through the interactive exercises on RUST BY PRACTICE <a href=\"https:\/\/practice.course.rs\/\" rel=\"noopener noreferrer\">website<\/a>.<\/p>\n\n<p>This resource was incredibly helpful for immediately applying the concepts I was learning. Being able to modify and run small snippets directly in the browser solidified my understanding of:<\/p>\n\n<ul>\n<li>How different data types behave.<\/li>\n<li>The practical implications of mutability.<\/li>\n<li>Seeing ownership and borrowing errors in action and figuring out how to fix them.<\/li>\n<\/ul>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxweox5jul08ve7ecfrkz.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxweox5jul08ve7ecfrkz.png\" alt=\"Rust By practice\" width=\"800\" height=\"449\"><\/a><\/p>\n\n<p>I highly recommend it as a companion to \"The Rust Programming Language\" book. It truly helps bridge the gap between theory and practice.<\/p>\n\n<p>Learning resources I found useful so far for the fundamentals include;<\/p>\n\n<ul>\n<li><a href=\"https:\/\/practice.course.rs\/\" rel=\"noopener noreferrer\">Rust by practice<\/a><\/li>\n<li><a href=\"https:\/\/www.rust-lang.org\/\" rel=\"noopener noreferrer\">Official Rust documentation<\/a><\/li>\n<li><a href=\"https:\/\/youtu.be\/BpPEoZW5IiY?si=ve1hJKbghXLCHaIf\" rel=\"noopener noreferrer\">FreeCodeCamp Rust video course<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Lymah123\/RustBooks\" rel=\"noopener noreferrer\">Books<\/a><\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Week 1 Reflections\n<\/h3>\n\n<p>This first week has been an intense introduction. Rust's compiler can feel like a strict teacher, but every error message is a lesson. Ownership, references, and borrowing, along with the underlying memory model of the Heap and Stack, are definitely the most challenging parts, but I can already see the immense power they offer in terms of memory safety and performance.<\/p>\n\n<p>My AI assistant has been invaluable for getting quick explanations and analogies, acting as a personal tutor when \"The Book\" felt a bit too dense on a particular point. However, it reinforced that my active understanding is paramount; the AI provides guidance, but the learning and critical evaluation are entirely human.<\/p>\n\n<p>Follow me on my favorite place <a href=\"https:\/\/github.com\/Lymah123\" rel=\"noopener noreferrer\">here<\/a>.<\/p>\n\n<p><strong><em>See ya in week 2.<\/em><\/strong><\/p>\n\n","category":["rust","learning","beginners","ai"]}]}}