Production-ready AI agent that analyzes GitHub repositories and generates comprehensive step-by-step tutorials with working code examples.
- Single-Agent System: Single LangGraph agent that uses 5 tools to orchestrate the entire workflow for repository discovery, analysis, and tutorial generation
- Async Processing: Background job processing with Celery + Redis
- Production Ready: Optimized for Render.com free tier (512MB RAM, 25MB storage)
- Cost Optimized: Uses Claude Haiku only, aggressive caching, sequential processing
- Python 3.11+
- Git
- Docker Desktop (for local development)
- GitHub account
- Render.com account (free)
- Anthropic API key
- GitHub Personal Access Token
Anthropic API Key:
- Go to https://console.anthropic.com
- Sign up/login
- Navigate to "API Keys" in settings
- Click "Create Key"
- Copy key (starts with
sk-ant-...) - Free tier: $5 credits included
GitHub Token:
- GitHub β Settings β Developer settings β Personal access tokens β Tokens (classic)
- Click "Generate new token"
- Select scopes:
public_repo(read-only access to public repositories) - Copy token
- Store securely (won't be shown again)
git clone <your-repo-url>
cd git_agent# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Add to PATH (add to ~/.bashrc or ~/.zshrc for persistence)
export PATH="$HOME/.cargo/bin:$PATH"# Create virtual environment and install dependencies using uv sync
# This reads from pyproject.toml and automatically creates .venv
uv sync
# Activate virtual environment (uv sync creates it automatically)
# macOS/Linux:
source .venv/bin/activate
# Windows:
.venv\Scripts\activateNote: uv sync automatically:
- Creates a virtual environment (
.venv/) - Installs all dependencies from
pyproject.toml - Locks versions for reproducibility
Adding new dependencies:
# Add a new dependency
uv add package-name
# Add a dev dependency
uv add --dev package-name
# This automatically updates pyproject.tomlNote: requirements.txt is kept for Docker compatibility. To regenerate it from pyproject.toml:
uv pip compile pyproject.toml -o requirements.txtcp .env.example .env
# Edit .env with your API keys# Start PostgreSQL and Redis
docker-compose up -d
# Initialize database
alembic upgrade head
# Start FastAPI server (Terminal 1)
uvicorn app.main:app --reload --port 8000
# Start Celery worker (Terminal 2)
celery -A app.celery_app worker --loglevel=infocurl http://localhost:8000/healthExpected response:
{
"status": "healthy",
"database": "connected",
"redis": "connected",
"worker": "active"
}- Push code to GitHub
- Have API keys ready
- Ensure
render.yamlis in repository
-
Create Render Account
- Go to https://render.com
- Sign up with GitHub
- Authorize repository access
-
Deploy from Blueprint
- Dashboard β "New +" β "Blueprint"
- Connect GitHub repository
- Render detects
render.yamlautomatically - Review services: Web Service, Worker, PostgreSQL, Redis
- Click "Apply"
-
Configure Environment Variables
For Web Service (
tutorial-generator-api):- Service β "Environment" tab
- Add:
ANTHROPIC_API_KEY= your_key - Add:
GITHUB_TOKEN= your_token - Click "Save Changes"
For Worker Service (
tutorial-generator-worker):- Repeat same environment variables
-
Monitor Deployment
- Check "Events" tab for progress
- Wait 5-10 minutes for initial build
- Verify all 4 services show "Live" status
-
Verify Deployment
curl https://your-app-name.onrender.com/health
- API Docs:
https://your-app-name.onrender.com/docs - Monitor logs in Render dashboard
- Set up database backups (optional)
Generate a tutorial for a technology.
Request:
curl -X POST https://your-app.onrender.com/api/v1/generate \
-H "Content-Type: application/json" \
-d '{"technology": "FastAPI", "max_repos": 3}'Response:
{
"job_id": "abc123",
"status": "queued",
"message": "Tutorial generation started"
}Get job status.
Response:
{
"job_id": "abc123",
"status": "processing",
"progress": 45,
"created_at": "2024-01-01T00:00:00Z"
}Get completed tutorial.
Response:
{
"job_id": "abc123",
"status": "completed",
"tutorial": {
"title": "Complete FastAPI Tutorial",
"sections": [...],
"code_examples": [...]
}
}Cancel a running job.
Health check endpoint.
Generate Tutorial:
curl -X POST http://localhost:8000/api/v1/generate \
-H "Content-Type: application/json" \
-d '{"technology": "Redis"}'Check Status:
curl http://localhost:8000/api/v1/jobs/{job_id}Poll for Completion:
while true; do
STATUS=$(curl -s http://localhost:8000/api/v1/jobs/{job_id} | jq -r '.status')
echo "Status: $STATUS"
[ "$STATUS" = "completed" ] && break
sleep 10
done-
Stop Services:
- Dashboard β Each service β "Suspend"
-
Delete Services (in order):
- Web Service β Settings β "Delete Web Service" β Confirm
- Worker β Settings β "Delete Background Worker" β Confirm
- PostgreSQL β Settings β "Delete Database" β Type name β Confirm
- Redis β Settings β "Delete Redis Instance" β Confirm
-
Verify:
- Dashboard shows no services
- Billing shows $0/month
- Dashboard β Service β "Suspend"
- Resume anytime with "Resume" button
Note: Free tier databases reset after 90 days of inactivity.
Service won't start:
- Check environment variables are set
- Review logs in Render dashboard
- Verify database connection string
Build failures:
- Check
pyproject.tomlsyntax - Verify Python version (3.11+)
- Review build logs for errors
Cold start delays:
- First request after 15min inactivity takes ~30s
- Normal for free tier (service auto-sleeps)
Out of memory:
- Reduce
max_reposto 2 - Check for memory leaks in logs
- Restart service
Rate limit exceeded:
- Limit: 10 requests/hour per IP
- Wait before retrying
- Use rate limiting headers in response
Docker not starting:
docker-compose down
docker-compose up -dDatabase connection refused:
- Verify PostgreSQL is running:
docker ps - Check connection string in
.env
Dependencies not installing:
- Make sure uv is in PATH:
which uv - Try:
uv sync --reinstall
- RAM: 512MB (strict limit)
- Storage: 25MB PostgreSQL, 25MB Redis
- Uptime: 750 hours/month
- Auto-sleep: After 15min inactivity (30s cold start)
- Database: Resets after 90 days inactivity
- Processing: Max 3 repos, 10min timeout, sequential only
Free Tier (First Month):
- Render: $0
- Anthropic: $5 free credits (~20-50 tutorials)
- Total: FREE
After Free Credits:
- Render: $0
- Anthropic: ~$0.10 per tutorial
- 100 tutorials/month: ~$10
Paid Upgrade (Optional):
- Render Starter: $7/service
- Total: $21/month (API + Worker + DB)
- Benefits: No cold starts, more RAM, persistent DB
βββββββββββββββ
β FastAPI β
β (API) β
ββββββββ¬βββββββ
β
ββββΊ Celery Worker βββΊ LangGraph Agent
β βββ Single Agent with 5 Tools
β βββ search_github_repositories
β βββ analyze_repository_structure
β βββ get_repository_code_samples
β βββ synthesize_patterns
β βββ calculate_quality_score
β
ββββΊ PostgreSQL (Jobs/Results)
β
ββββΊ Redis (Cache/Queue)
The tutorial generation is powered by a single LangGraph agent that uses 5 tools to orchestrate the entire workflow. This simpler architecture is more efficient and easier to maintain than a multi-agent system.
graph TD
A[Start] --> B[Single Tutorial Agent]
B --> C{Tool Call?}
C -->|Yes| D[Execute Tool]
C -->|No| E[Generate Content]
D --> F[Update State]
E --> F
F --> G{Complete?}
G -->|No| B
G -->|Yes| H[End]
style B fill:#e1f5ff
style D fill:#fff4e1
style E fill:#e8f5e9
Tutorial Agent - One LLM-powered agent that orchestrates the entire workflow:
- LLM: Claude Haiku (claude-3-haiku-20240307)
- Purpose: Decide which tools to use and generate tutorial content
- Process:
- Receives state and decides next action
- Calls appropriate tools when needed
- Generates content using LLM when ready
- Updates progress and state after each step
1. search_github_repositories(query, max_results) (Progress: 0-10%)
- Purpose: Search and rank GitHub repositories
- Process:
- Searches GitHub using query:
"{technology} production best practices" - Sorts by stars (most popular first)
- Returns top N repositories (default: 3, max: 3)
- Results cached for 1 hour in Redis
- Searches GitHub using query:
- Output: List of repository metadata (name, stars, description, URL)
2. analyze_repository_structure(repo_url) (Progress: 10-40%)
- Purpose: Analyze repository structure and extract metadata
- Process:
- Extracts file structure (important files only)
- Retrieves README content (first 5KB)
- Extracts topics and metadata
- Results cached per repository for 1 hour
- Output: Repository structure with files, topics, and README
3. get_repository_code_samples(repo_url, file_paths) (Progress: 10-40%)
- Purpose: Extract code samples from specific files
- Process:
- Gets code from top 5 key files (max 10KB each)
- Only retrieves files < 50KB
- Results cached for 1 hour
- Output: Dictionary mapping file paths to code content
4. synthesize_patterns(analyzed_repos) (Progress: 40-60%)
- Purpose: Aggregate findings and extract common patterns
- Process:
- Identifies common file structures across repositories
- Extracts shared topics and themes
- Compiles best practices from READMEs
- Builds architecture overview
- Output: Patterns, best practices list, architecture notes
5. calculate_quality_score(tutorial_content, errors) (Progress: 90-100%)
- Purpose: Validate tutorial completeness and quality
- Process:
- Calculates quality score (0-100):
- Deducts points for errors
- Checks section completeness
- Validates content length
- Calculates quality score (0-100):
- Output: Quality score (0-100)
When the agent has collected all repository data, it uses the LLM directly (no tools) to:
- Generate comprehensive tutorial content
- Create sections: Introduction, Getting Started, Architecture Patterns, Best Practices, Code Examples, Deployment
- Incorporate code examples and best practices from analyzed repos
- Produce production-focused, practical content
All agents share a TypedDict state (AgentState) that includes:
{
"technology": str, # Input technology name
"max_repos": int, # Max repos to analyze
"repositories": list[dict], # Discovered repos
"analyzed_repos": list[dict], # Analyzed repo data
"patterns": list[dict], # Extracted patterns
"best_practices": list[str], # Best practices list
"architecture": dict, # Architecture overview
"tutorial_structure": dict, # Planned structure
"tutorial_content": dict, # Generated content
"quality_score": float, # Quality score (0-100)
"errors": list[str], # Error messages
"progress": int, # Progress (0-100)
"current_step": str, # Current agent step
}GitHub API Tools:
search_github_repositories(query, max_results)- Search GitHub reposanalyze_repository_structure(repo_url)- Get repo structure and metadataget_repository_code_samples(repo_url, file_paths)- Extract code from files
Caching Strategy:
- All GitHub API calls cached in Redis (1 hour TTL)
- Reduces API rate limit issues
- Speeds up repeated requests
- Cache keys:
github_search:{query},repo_structure:{repo}, etc.
Memory Optimization:
- β Sequential processing (one repo at a time)
- β Limits: 3 repos max, 5 files per repo, 10KB per file
- β Aggressive caching to reduce API calls
- β Progress tracking for monitoring
Cost Optimization:
- β Claude Haiku only (cheapest model)
- β Cached LLM responses where possible
- β Limited token usage per section
- β No parallel processing (saves memory)
Performance:
- β Redis caching for all external API calls
- β Database connection pooling (2 connections)
- β Timeout: 10 minutes per job
- β Progress updates to database
- User Request β FastAPI receives request
- Job Creation β Job record created in PostgreSQL
- Celery Task β Background task queued in Redis
- LangGraph Execution β Single agent orchestrates workflow:
- Agent decides which tool to call based on current state
- Tools execute and return results
- State updated after each tool execution
- Agent generates content when all data collected
- Progress tracked in database
- Errors collected in state
- Result Storage β Final tutorial stored in job.result (JSON)
- User Retrieval β User polls for completion and retrieves result
- Agent and tools have try-except blocks
- Errors collected in
state["errors"]list - Job marked as failed if critical errors occur
- Partial results saved if possible
- Maximum 2 retries on transient failures
Advantages:
- β Simpler Architecture: One agent is easier to understand and maintain
- β More Flexible: LLM can decide tool order dynamically
- β Less Overhead: Fewer function calls and state transitions
- β Better Tool Integration: Tools are first-class citizens, not separate agents
- β Easier Debugging: Single point of control for the workflow
Trade-offs:
- Most steps are deterministic (tool calls), not agent decisions
- Only content generation truly needs LLM reasoning
- Simpler is better for this use case
MIT License - see LICENSE file for details
Contributions welcome! Please open an issue or submit a PR.