Skip to main content
< All Topics
Print

Chapter 16: Python Services

Chapter 16: Python Services

Last Updated: 2026-03

## 16.1 Overview

Python is used for two distinct types of ITI services:

| Type | Framework | Example | Location |

|——|———–|———|———|

| Scheduled agents | Flask + APScheduler | Patriot Agent | Personal/patriot-agent/ |

| API services | FastAPI | General pattern (available for new services) | Pattern in ITI/shared/patterns/ |

| Infrastructure tests | pytest | n8n/Dify test suite | ITI/infrastructure/n8n-dify/tests/ |

All Python services use the system Python at /opt/anaconda3/bin/python unless otherwise noted.

16.2 Flask Pattern — Patriot Agent

The Patriot Agent is a Flask web service that aggregates news, analyzes it with Claude, and delivers reports on a schedule.

Project structure


patriot-agent/
├── app.py                  # Flask application factory
├── scheduler.py            # APScheduler job definitions
├── services/
│   ├── claude_service.py   # Anthropic Claude integration
│   ├── tavily_service.py   # Tavily web search
│   └── rss_service.py      # feedparser RSS ingestion
├── models/
│   └── report.py           # Data models
├── templates/              # Jinja2 HTML templates
├── requirements.txt        # Dependencies
├── .env                    # Secrets (not committed)
└── CLAUDE.md

Application factory pattern


# app.py
from flask import Flask
from .scheduler import init_scheduler

def create_app() -> Flask:
    app = Flask(__name__)
    app.config.from_object('config.ProductionConfig')

    # Initialize services
    init_scheduler(app)

    # Register blueprints
    from .routes import main_bp
    app.register_blueprint(main_bp)

    return app

APScheduler integration

APScheduler runs background jobs on a cron schedule within the Flask process:


# scheduler.py
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger

def init_scheduler(app: Flask) -> None:
    scheduler = BackgroundScheduler()

    scheduler.add_job(
        func=run_daily_report,
        trigger=CronTrigger(hour=7, minute=0),  # 7:00 AM daily
        id='daily_report',
        replace_existing=True,
    )

    scheduler.start()

Claude integration


# services/claude_service.py
import anthropic
import os

class ClaudeService:
    def __init__(self):
        self._client = anthropic.Anthropic(api_key=os.environ['ANTHROPIC_API_KEY'])

    def analyze(self, content: str, system_prompt: str) -> str:
        message = self._client.messages.create(
            model="claude-opus-4-5",
            max_tokens=4096,
            system=system_prompt,
            messages=[{"role": "user", "content": content}]
        )
        return message.content[0].text

Tavily search integration


# services/tavily_service.py
from tavily import TavilyClient
import os

class TavilyService:
    def __init__(self):
        self._client = TavilyClient(api_key=os.environ['TAVILY_API_KEY'])

    def search(self, query: str, max_results: int = 10) -> list[dict]:
        response = self._client.search(query=query, max_results=max_results)
        return response.get('results', [])

16.3 FastAPI Pattern

FastAPI is the pattern for new Python API services that require:

  • High performance (async)
  • Automatic OpenAPI documentation
  • Pydantic input validation

Project structure


my-fastapi-service/
├── main.py                 # FastAPI app + router registration
├── routers/
│   ├── ai.py               # AI-related endpoints
│   └── health.py           # Health check endpoint
├── schemas/
│   └── requests.py         # Pydantic request/response models
├── services/
│   └── claude_service.py   # AI service layer
├── dependencies.py         # FastAPI dependency injection
├── requirements.txt
└── CLAUDE.md

App setup


# main.py
from fastapi import FastAPI
from .routers import ai, health

app = FastAPI(
    title="ITI AI Service",
    version="1.0.0",
    docs_url="/docs",  # Disable in production if not needed
)

app.include_router(health.router)
app.include_router(ai.router, prefix="/api/v1")

Pydantic models


# schemas/requests.py
from pydantic import BaseModel, Field

class AIRequest(BaseModel):
    user_message: str = Field(..., min_length=1, max_length=10000)
    context: str | None = None
    max_tokens: int = Field(default=2048, ge=1, le=8192)

class AIResponse(BaseModel):
    content: str
    model: str
    usage: dict

Async endpoint


# routers/ai.py
from fastapi import APIRouter, Depends, HTTPException
from ..schemas.requests import AIRequest, AIResponse
from ..services.claude_service import ClaudeService

router = APIRouter()

async def get_claude_service() -> ClaudeService:
    return ClaudeService()

@router.post("/complete", response_model=AIResponse)
async def complete(
    request: AIRequest,
    claude: ClaudeService = Depends(get_claude_service),
) -> AIResponse:
    try:
        result = await claude.complete(request.user_message, request.context)
        return AIResponse(**result)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Running with Uvicorn


uvicorn main:app --host 0.0.0.0 --port 8000 --reload

16.4 Environment Variables

All Python services read configuration from environment variables. Never hardcode secrets.

Standard pattern


import os
from dotenv import load_dotenv

load_dotenv()  # Load .env file for local development

# Validate required variables at startup
REQUIRED_ENV_VARS = ['ANTHROPIC_API_KEY', 'TAVILY_API_KEY']
missing = [v for v in REQUIRED_ENV_VARS if not os.environ.get(v)]
if missing:
    raise EnvironmentError(f"Missing required environment variables: {missing}")

ANTHROPIC_API_KEY = os.environ['ANTHROPIC_API_KEY']

16.5 Dependencies

Use requirements.txt for all Python services. Pin major versions:


anthropic>=0.40.0,<1.0
flask>=3.0.0,<4.0
flask-apscheduler>=1.13.0,<2.0
fastapi>=0.115.0,<1.0
uvicorn[standard]>=0.32.0,<1.0
pydantic>=2.0.0,<3.0
httpx>=0.27.0,<1.0
tavily-python>=0.5.0,<1.0
feedparser>=6.0.0,<7.0
python-dotenv>=1.0.0,<2.0

Install:


pip install -r requirements.txt

Previous: Chapter 15 — Desktop Apps with Tauri 2 | Next: Chapter 17 — iOS & macOS with Swift

Table of Contents