Development
Day-to-day development workflow, code quality, testing, and Docker.
Important
Configure cloud resource values in .env after first deployment. See Getting Started for initial setup and Environment Variables for complete reference.
Quick Start
Local-only (cloud resource URIs commented out in .env):
uv run server # API at 127.0.0.1:8000 (SQLite sessions, in-memory storage)
SERVE_WEB_INTERFACE=TRUE uv run server # With ADK web UI
Standard development (mirrors production, requires deployed cloud resource URIs configured in .env):
Both modes always export traces and structured logs to Cloud Trace and Cloud Logging. Set TELEMETRY_NAMESPACE in .env to a unique value (e.g., your name) so teammates can filter to your traces when reviewing experiments.
Prerequisites:
- .env file configured with required authentication and identification values (copy from .env.example)
- gcloud auth application-default login (for Vertex AI and telemetry)
See Getting Started for initial setup.
Environment Setup
Configure your local .env file after completing your first deployment. The deployed resources provide production-ready persistence for sessions, memory, and artifacts.
1. Create .env File
2. Configure Environment Variables
Edit .env and configure required values. The .env.example file includes inline comments for each variable.
Required configuration:
- Google Cloud Vertex AI credentials
- Agent identification
- OpenTelemetry settings
Recommended (after first deployment):
- BASTION_INSTANCE - Bastion host name for IAP tunnel (docker-compose)
- BASTION_ZONE - Bastion host zone for IAP tunnel (docker-compose)
- SESSION_SERVICE_URI - Session persistence (Cloud SQL)
- MEMORY_SERVICE_URI - Memory persistence (Agent Engine)
- ARTIFACT_SERVICE_URI - Artifact storage
See Environment Variables for complete reference.
3. Verify Configuration
# Check auth
gcloud auth application-default login
# Verify with Docker Compose (starts server and connects to cloud resources configured above)
docker compose up --build --watch
See Environment Variables for complete reference.
Feature Branch Workflow
# Create branch (feat/, fix/, docs/, refactor/, test/)
git checkout -b feat/your-feature-name
# Develop locally
docker compose up --build --watch # Standard (cloud resources, mirrors production)
# Or: uv run server # Local-only with cloud resource URIs commented out in .env
# Quality checks before commit (100% coverage required)
uv run ruff format && uv run ruff check && uv run mypy
uv run pytest --cov --cov-report=term-missing
# Commit (Conventional Commits: 50 char title, list body)
git add . && git commit -m "feat: add new tool"
# Push and create PR
git push origin feat/your-feature-name
gh pr create # Follow PR format: What, Why, How, Tests
# After merge to main, monitor deployment
gh run list --workflow=ci-cd.yml --limit 5
gh run view --log
GitHub Actions automatically builds, tests, and deploys to Cloud Run. Check job summary for deployment details.
Code Quality & Testing
Run format, lint, type check, and unit tests (100% coverage required) before every commit
Standards:
- Type Hints: Strict mypy, modern Python 3.13+ syntax (| unions, lowercase generics)
- Code Style: Ruff enforced (88-char lines, Path objects, security checks)
- Docstrings: Google-style format (args, returns, exceptions)
- Testing: 100% coverage on production code, exclusions for configuration modules, fixtures in conftest.py, test behaviors and errors
See Testing Strategy and Code Quality references for detailed patterns, tool usage, and exclusion strategies.
Docker Compose for Standard Development
Docker Compose reads .env values and mirrors the production Cloud Run architecture: IAP tunnel to bastion → Auth Proxy → Cloud SQL private IP, with file sync and auto-restart (~2-5s feedback loop).
# Start with watch mode (leave running)
docker compose up --build --watch
# Changes in src/ sync instantly
# Changes in pyproject.toml or uv.lock trigger rebuild
# Stop: Ctrl+C or docker compose down
Important
Docker Compose requires roles/iap.tunnelResourceAccessor on your Google account for IAP tunnel access. Grant via gcloud projects add-iam-policy-binding or GCP Console.
Key details:
- IAP tunnel container connects to bastion host running Auth Proxy, sharing app's localhost via network_mode: "service:app"
- App connects to localhost:5432 identically to Cloud Run
- Source files sync to container without rebuild (instant feedback)
- Loads .env automatically for configuration
- Multi-stage Dockerfile optimized with uv cache mounts (~80% faster rebuilds)
- Non-root container (~200MB final image)
Local-Only (uv run server)
uv run server reads .env like Docker Compose. With cloud resource URIs set, it connects to those services. For fully local development, comment out SESSION_SERVICE_URI, MEMORY_SERVICE_URI, and ARTIFACT_SERVICE_URI in .env. Sessions persist locally in SQLite (.adk/ directory). Traces and logs still export to Cloud Trace and Cloud Logging.
uv run server # Uses cloud resources if URIs set, local storage if unset
SERVE_WEB_INTERFACE=TRUE uv run server # With ADK web UI
LOG_LEVEL=DEBUG uv run server # Debug logging
You can also connect uv run server to Cloud SQL, Agent Engine, or GCS selectively by setting individual service URI environment variables. See Cloud Backend Options for manual IAP tunnel setup and selective backend options.
See Docker Compose Workflow and Dockerfile Strategy for details on watch mode, volumes, layer optimization, and security.
Common Tasks
Dependencies
# Add runtime dependency
uv add package-name
# Add dev dependency
uv add --group dev package-name
# Update all dependencies
uv lock --upgrade
# Update specific package
uv lock --upgrade-package package-name
# After updating pyproject.toml or uv.lock:
# - Locally: Restart server or Docker Compose (auto-rebuild with watch)
# - CI/CD: Commit both files together (required for --locked to pass)
Version Bump
When bumping version in pyproject.toml:
# Edit version in pyproject.toml
# Then update lockfile
uv lock
# Commit both together
git add pyproject.toml uv.lock
git commit -m "chore: bump version to X.Y.Z"
Why: CI uses uv sync --locked which will fail if lockfile is out of sync.
Custom GCP Services or IAM Roles
Need a new GCP API or WIF IAM role for your feature? Add it to the designated main module extension points — no bootstrap re-run or admin required.
terraform/main/services.tf— add to theservicesset to enable a GCP APIterraform/main/iam.tf— add to thewif_additional_rolesset to grant the GitHub Actions WIF principal a new role
Add the roles or services AND the resources that use them in the same PR. The time_sleep resources handle propagation within the apply — declare depends_on on the correct sleep instance(s) for any resource that requires a newly-enabled service or role.
See Extending the Main Module for the full pattern, code examples, and rationale.
Test Deployed Service
Proxy Cloud Run service to test locally:
# Service name format: ${agent_name}-${environment}
gcloud run services proxy <service-name> \
--project <project-id> \
--region <region> \
--port 8000
# Test
curl http://localhost:8000/health
# With web UI (if SERVE_WEB_INTERFACE=TRUE)
open http://localhost:8000
# Stop proxy: Ctrl+C
See Cloud Run proxy documentation.
Observability
Server Logs:
- Print to stdout (via LoggingPlugin callbacks)
- Basic request/response logging for immediate feedback
Opentelemetry Traces and Logs:
- Detailed traces → Cloud Trace
- Structured logs → Cloud Logging
- Full correlation between traces and logs
See Observability for querying, filtering, and trace analysis.
Project Structure
your-agent-name/
src/your_agent_name/
agent.py # ADK App and LlmAgent configuration
callbacks.py # Agent lifecycle callbacks (logging, safety, tool augmentation)
prompt.py # Agent instructions (InstructionProvider pattern)
server.py # FastAPI composition root (services, DI, routing)
tools.py # Custom FunctionTools for agent use
utils/ # Config validation, common helpers, observability
tests/ # Test suite
conftest.py # Shared fixtures, test env setup
test_*.py # Tests mirror source module structure
terraform/ # Infrastructure as code
bootstrap/{env} # One-time CI/CD setup per environment
main/ # Agent cloud resource deployment
docs/ # Documentation
.env.example # Environment template
pyproject.toml # Project configuration
docker-compose.yml # Local development
Dockerfile # Container image
AGENTS.md # AI Coding Agent instructions
CLAUDE.md # Imports AGENTS.md for Claude Code
README.md # Main documentation