{"owner":"GoogleCloudPlatform","repo":"agent-starter-pack","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["GEMINI.md"],"skills":{"GEMINI.md":"# Agent Starter Pack - AI Coding Agent Guide\n\n> **Scope**: This document is for AI coding agents contributing to the **Agent Starter Pack repository itself** (the template generator). For guidance on working with **generated projects**, see [llm.txt](./llm.txt).\n\nThis document provides essential guidance, architectural insights, and best practices for AI coding agents tasked with modifying the Google Cloud Agent Starter Pack. Adhering to these principles is critical for making safe, consistent, and effective changes.\n\n---\n\n## Core Principles for AI Agents\n\n1.  **Preserve and Isolate:** Your primary objective is surgical precision. Modify *only* the code segments directly related to the user's request. Preserve all surrounding code, comments, and formatting. Do not rewrite entire files or functions to make a small change.\n2.  **Follow Conventions:** This project relies heavily on established patterns. Before writing new code, analyze the surrounding files to understand and replicate existing conventions for naming, templating logic, and directory structure.\n3.  **Template-First Mindset:** ASP is a template generator. The CLI should remain lean with good defaults. Most features belong in templates, not CLI code.\n4.  **Search Comprehensively:** A single change often requires updates in multiple places. When modifying configuration, variables, or infrastructure, you **must** search across the entire repository, including:\n    *   `agent_starter_pack/base_templates/` (core templates by language)\n    *   `agent_starter_pack/deployment_targets/` (environment-specific overrides)\n    *   `.github/` and `.cloudbuild/` (CI/CD workflows)\n    *   `docs/` (user-facing documentation)\n\n---\n\n## Project Architecture Overview\n\n### 4-Layer Template System\n\nTemplate processing follows this hierarchy (later layers override earlier ones):\n\n| Layer | Directory | Purpose |\n|-------|-----------|---------|\n| 1. Base | `agent_starter_pack/base_templates/<language>/` | Core Jinja scaffolding (Python, Go, more coming) |\n| 2. Deployment | `agent_starter_pack/deployment_targets/` | Environment overrides (cloud_run, gke, agent_engine) |\n| 3. Frontend | `agent_starter_pack/frontends/` | UI-specific files |\n| 4. Agent | `agent_starter_pack/agents/*/` | Agent-specific logic and configurations |\n\n**Rule**: Always place changes in the correct layer. Check if deployment targets need corresponding updates.\n\n### Key Directory Structure\n\n```\nagent_starter_pack/\n├── agents/                    # Agent-specific files\n│   ├── adk/                   # Base ADK agent (Python)\n│   ├── adk_a2a/               # A2A-enabled ADK agent\n│   ├── adk_go/                # Base ADK agent (Go)\n│   ├── adk_live/              # Real-time multimodal agent\n│   ├── agentic_rag/           # RAG agent\n│   └── langgraph/             # LangGraph-based agent\n├── base_templates/            # Core Jinja templates by language\n│   ├── python/                # Python project template\n│   │   ├── {{cookiecutter.agent_directory}}/\n│   │   ├── deployment/\n│   │   ├── tests/\n│   │   └── Makefile\n│   └── go/                    # Go project template\n├── deployment_targets/        # Environment-specific overrides\n│   ├── agent_engine/          # Agent Engine deployment\n│   ├── cloud_run/             # Cloud Run deployment\n│   └── gke/                   # GKE Autopilot deployment\n├── frontends/                 # UI templates\n└── cli/                       # CLI implementation\n    ├── commands/              # create, setup-cicd, enhance, etc.\n    └── utils/                 # Template processing, helpers\n```\n\n### When to Modify What\n\n| Change Type | Where to Modify | Also Check |\n|-------------|-----------------|------------|\n| Affects ALL generated projects | `base_templates/<language>/` | Deployment targets for conflicts |\n| Deployment-specific logic | `deployment_targets/<target>/` | Base templates for shared code |\n| Agent-specific feature | `agents/<agent>/` | Other agents for consistency |\n| New CLI flag/command | `cli/commands/` | `cli/utils/` for shared logic |\n| CI/CD changes | Both `.github/` AND `.cloudbuild/` | Keep in sync |\n| Documentation | `docs/` | README.md for overview changes |\n\n### Template Processing Flow\n\n1.  **Variable resolution** from `cookiecutter.json`\n2.  **File copying** (base → deployment → frontend → agent overlays)\n3.  **Jinja2 rendering** of file content\n4.  **File/directory name rendering** (Jinja in filenames)\n\n### Cross-File Dependencies\n\nChanges often require coordinated updates:\n- **Configuration**: `templateconfig.yaml` → `cookiecutter.json` → rendered templates\n- **CI/CD**: `.github/workflows/` ↔ `.cloudbuild/` (must stay in sync)\n- **Infrastructure**: Base terraform → deployment target overrides\n\n---\n\n## Template Development Workflow\n\nTemplate changes require a specific workflow because you're modifying Jinja templates, not regular source files.\n\n> **Note:** This workflow applies to both Python and Go templates. Both use Jinja templating with the same patterns (`{{cookiecutter.*}}`, `{% if %}`, etc.).\n\n### Step-by-Step Process\n\n#### 1. Generate a Test Instance\n\n```bash\nuv run agent-starter-pack create mytest -p -s -y -d cloud_run --output-dir target\n```\n\nFlags explained:\n- `-p` / `--prototype`: Minimal project (no CI/CD or Terraform)\n- `-s` / `--skip-checks`: Skip GCP/Vertex AI verification\n- `-y` / `--auto-approve`: Skip all confirmation prompts\n- `-d`: Deployment target\n- `--output-dir target`: Output to target/ (gitignored)\n\n#### 2. Initialize Git in the Generated Project\n\n```bash\ncd target/mytest && git init && git add . && git commit -m \"Initial\"\n```\n\nThis creates a baseline for tracking your changes with `git diff`.\n\n#### 3. Develop with Tight Feedback Loops\n\n- Make changes directly in `target/mytest/`\n- Test immediately: `make lint`, run the code, check output\n- Iterate until the change works correctly\n- Use `git diff` to see exactly what you changed\n\n#### 4. Backport Changes to Jinja Templates\n\n- Find the source template: `find agent_starter_pack -name \"filename.py\" -type f`\n- Apply your changes to the template file\n- Add Jinja conditionals if the change is conditional\n- Use `{%- -%}` whitespace control carefully\n\n#### 5. Validate Across Combinations\n\n```bash\n# Test your target combination\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# Test alternate agent with same deployment\n_TEST_AGENT_COMBINATION=\"adk_live,cloud_run\" make lint-templated-agents\n\n# Test same agent with alternate deployment\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n```\n\n### Why This Workflow?\n\n- Jinja templates are harder to debug than rendered code\n- Generated projects give immediate feedback on syntax errors\n- Backporting ensures you understand exactly what changed\n- Cross-combination testing catches conditional logic bugs\n\n### Language-Specific Notes\n\nThe template development workflow above applies to all languages. Here are language-specific details:\n\n| Language | Agent(s) | Linter | Test Command | Status |\n|----------|----------|--------|--------------|--------|\n| Python | adk, adk_a2a, adk_live, agentic_rag, langgraph, custom_a2a | `ruff`, `ty` | `make lint` | Production |\n| Go | adk_go | `golangci-lint` | `make lint` | Production |\n| Java | (coming soon) | - | - | In development |\n| TypeScript | (coming soon) | - | - | In development |\n\n**Python example:**\n```bash\nuv run agent-starter-pack create mytest -a adk -d cloud_run -p -s -y --output-dir target\n```\n\n**Go example:**\n```bash\nuv run agent-starter-pack create mytest -a adk_go -d cloud_run -p -s -y --output-dir target\n```\n\n---\n\n## Jinja Templating Rules\n\n> **Note:** These rules apply to both Python and Go templates. Both languages use the same Jinja2 templating patterns.\n\n### Templating Engine: Cookiecutter + Jinja2\n\nThe starter pack uses **Cookiecutter** to generate project scaffolding from templates customized with **Jinja2**. Understanding the rendering process is key to avoiding errors.\n\n**Multi-Phase Template Processing:**\n\n1.  **Cookiecutter Variable Substitution:** Replacement of `{{cookiecutter.variable_name}}` placeholders\n2.  **Jinja2 Logic Execution:** Conditional blocks (`{% if %}`), loops (`{% for %}`)\n3.  **File/Directory Name Templating:** Jinja2 in filenames is rendered\n\n### Block Balancing (Critical)\n\n**Every opening Jinja block must have a corresponding closing block.**\n\n-   `{% if ... %}` requires `{% endif %}`\n-   `{% for ... %}` requires `{% endfor %}`\n-   `{% raw %}` requires `{% endraw %}`\n\n```jinja\n{% if cookiecutter.deployment_target == 'cloud_run' %}\n  # Cloud Run specific content\n{% endif %}\n```\n\n### Variable Usage\n\nDistinguish between substitution and logic:\n\n-   **Substitution (in file content):** `{{ cookiecutter.project_name }}`\n-   **Logic (in `if`/`for` blocks):** `{% if cookiecutter.session_type == 'cloud_sql' %}`\n\n### Whitespace Control\n\nJinja is sensitive to whitespace. Use hyphens to control newlines:\n\n-   `{%-` removes whitespace before the block\n-   `-%}` removes whitespace after the block\n-   `{%- -%}` removes whitespace on both sides\n\n```jinja\n{%- if cookiecutter.some_option %}\noption = true\n{%- endif %}\n```\n\n### Conditional Logic Patterns\n\n```jinja\n{%- if cookiecutter.agent_name == \"adk_live\" %}\n# Agent-specific logic\n{%- elif cookiecutter.deployment_target == \"cloud_run\" %}\n# Deployment-specific logic\n{%- endif %}\n```\n\n---\n\n## Critical Whitespace Control Patterns\n\nJinja2 whitespace control is the #1 source of linting failures. Understanding these patterns is essential.\n\n### Pattern 1: Conditional Imports with Blank Line Separation\n\n**Problem:** Python requires blank lines to separate third-party imports from project imports. Conditional imports must handle this correctly.\n\n**Wrong - Creates extra blank line:**\n```jinja\nfrom opentelemetry.sdk.trace import TracerProvider, export\n{% if cookiecutter.session_type == \"agent_engine\" %}\nfrom vertexai import agent_engines\n{% endif %}\n\nfrom app.app_utils.gcs import create_bucket_if_not_exists\n```\n\n**Correct - Exactly one blank line:**\n```jinja\nfrom opentelemetry.sdk.trace import TracerProvider, export\n{% if cookiecutter.session_type == \"agent_engine\" -%}\nfrom vertexai import agent_engines\n{% endif %}\n\n{%- if cookiecutter.is_a2a %}\nfrom {{cookiecutter.agent_directory}}.agent import app as adk_app\n\n{% endif %}\nfrom {{cookiecutter.agent_directory}}.app_utils.gcs import create_bucket_if_not_exists\n```\n\n**Key points:**\n- Use `{%- -%}` to control BOTH sides when needed\n- The blank line AFTER the conditional import goes INSIDE the if block when needed\n- Test BOTH when condition is true AND false\n\n### Pattern 2: Long Import Lines\n\n**Problem:** Ruff enforces line length limits. Long import statements must be split.\n\n**Wrong - Too long:**\n```python\nfrom app.app_utils.typing import Feedback, InputChat, Request, dumps, ensure_valid_config\n```\n\n**Correct - Split with parentheses:**\n```python\nfrom app.app_utils.typing import (\n    Feedback,\n    InputChat,\n    Request,\n    dumps,\n    ensure_valid_config,\n)\n```\n\n### Pattern 3: File End Newlines\n\n**Problem:** Ruff requires exactly ONE newline at the end of every file.\n\n**Wrong - No newline:**\n```jinja\nagent_engine = AgentEngineApp(project_id=project_id)\n{%- endif %}\n```\n\n**Wrong - Extra newline:**\n```jinja\nagent_engine = AgentEngineApp(project_id=project_id)\n{%- endif %}\n\n```\n\n**Correct - Exactly one:**\n```jinja\nagent_engine = AgentEngineApp(project_id=project_id)\n{%- endif %}\n```\n\n**Key for nested conditionals:**\n```jinja\nagent_engine = AgentEngineApp(\n    app=adk_app,\n    artifact_service_builder=artifact_service_builder,\n)\n{%- endif -%}\n{% else %}\n\nimport logging\n```\n\nNotice `{%- endif -%}` to prevent blank line before the else block.\n\n### Whitespace Control Cheat Sheet\n\n```jinja\n# Remove whitespace BEFORE the tag\n{%- if condition %}\n\n# Remove whitespace AFTER the tag\n{% if condition -%}\n\n# Remove whitespace on BOTH sides\n{%- if condition -%}\n\n# Typical pattern for conditional imports\n{% if condition -%}\nimport something\n{% endif %}\n\n# Typical pattern for conditional code blocks with blank line before\n{%- if condition %}\n\nsome_code()\n{%- endif %}\n\n# Pattern for preventing blank line between consecutive conditionals\n{%- endif -%}\n{%- if next_condition %}\n```\n\n---\n\n## Testing Strategy\n\n### Testing Coverage Matrix\n\n**Critical Principle:** Template changes can affect MULTIPLE agent/deployment combinations. Test across combinations when making template modifications.\n\n| Dimension | Options |\n|-----------|---------|\n| Agents | adk, adk_a2a, adk_go, adk_live, agentic_rag, langgraph |\n| Deployments | cloud_run, gke, agent_engine |\n| Session types | in_memory, cloud_sql, agent_engine |\n| Features | data_ingestion, frontend_type |\n\n### Minimum Coverage Before PR\n\n- [ ] Your target combination\n- [ ] One alternate agent with same deployment target\n- [ ] One alternate deployment target with same agent\n\n### Linting Commands\n\n**IMPORTANT:** Only run linting when explicitly requested by the user. Do not proactively lint unless asked.\n\n```bash\n# Linting a specific combination\n_TEST_AGENT_COMBINATION=\"agent,target,--param,value\" make lint-templated-agents\n\n# Testing a specific combination\n_TEST_AGENT_COMBINATION=\"agent,target,--param,value\" make test-templated-agents\n```\n\n### Common Test Combinations\n\n```bash\n# Cloud Run combinations (Python)\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,in_memory\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk_live,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# Agent Engine combinations (Python)\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk_live,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"langgraph,agent_engine\" make lint-templated-agents\n\n# GKE combinations (Python)\n_TEST_AGENT_COMBINATION=\"adk,gke,--session-type,in_memory\" make lint-templated-agents\n\n# Go template testing\n_TEST_AGENT_COMBINATION=\"adk_go,cloud_run\" make lint-templated-agents\n\n# Go template testing (GKE)\n_TEST_AGENT_COMBINATION=\"adk_go,gke\" make lint-templated-agents\n\n# With session type variations\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,agent_engine\" make lint-templated-agents\n```\n\n### Testing Workflow for Template Changes\n\n**Before committing ANY template change:**\n\n```bash\n# 1. Test the specific combination you're working on\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# 2. Test related combinations (same deployment, different agents)\n_TEST_AGENT_COMBINATION=\"adk_live,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# 3. Test alternate code paths (different deployment, session types)\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n\n# 4. If modifying deployment target files, test all agents with that target\n# For agent_engine changes:\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk_live,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"langgraph,agent_engine\" make lint-templated-agents\n```\n\n**Golden Rule:** After ANY template change affecting imports, conditionals, or file endings, test AT LEAST 3 combinations:\n1. The target combination\n2. An alternate agent with same deployment\n3. An alternate deployment with same agent\n\n---\n\n## Debugging Linting Failures\n\n### Step 1: Identify the Exact Error\n\n```bash\n# Look for the diff output in the error message\n--- app/fast_api_app.py\n+++ app/fast_api_app.py\n@@ -21,6 +21,7 @@\n from opentelemetry import trace\n from vertexai import agent_engines\n+\n from app.app_utils.gcs import create_bucket_if_not_exists\n```\n\nThe `+` line shows what Ruff WANTS to add. In this case, it wants a blank line after `agent_engines`.\n\n### Step 2: Find the Generated File\n\n```bash\n# Generated files are in target/\ncat target/project-name/app/fast_api_app.py | head -30\n```\n\n### Step 3: Trace Back to Template\n\n```bash\n# Find the template source\nfind agent_starter_pack -name \"fast_api_app.py\" -type f\n```\n\n### Step 4: Check BOTH Branches of Conditionals\n\n- If `{% if condition %}` exists, test with condition true AND false\n- Use different agent combinations to toggle different conditions\n\n### Common Linting Errors and Fixes\n\n| Error | Cause | Fix |\n|-------|-------|-----|\n| Missing blank line between imports | Conditional import without proper spacing | Add blank line inside `{% if %}` block with correct `{%- -%}` control |\n| Extra blank line between imports | Jinja block creating unwanted newline | Use `{%- endif -%}` to strip both sides |\n| Missing newline at end of file | Template ends without final newline | Ensure template has exactly one blank line at end |\n| Extra blank line at end of file | Multiple newlines or `{% endif %}` creating extra line | Use `{%- endif -%}` pattern |\n| Line too long | Import statement exceeds limit | Split into multi-line with parentheses |\n\n### Files Most Prone to Linting Issues\n\n1. **`agent_engine_app.py`** (deployment_targets/agent_engine/)\n   - Multiple conditional paths (adk_live, adk_a2a, regular)\n   - End-of-file newline issues\n\n2. **`fast_api_app.py`** (deployment_targets/cloud_run/)\n   - Conditional imports (session_type, is_a2a)\n   - Long import lines\n   - Complex nested conditionals\n\n3. **Any file with `{% if cookiecutter.agent_name == \"...\" %}`**\n   - Different agents trigger different code paths\n   - Must test multiple agent types\n\n---\n\n## CI/CD Integration\n\nThe project maintains parallel CI/CD implementations. **Any change to CI/CD logic must be applied to both.**\n\n-   **GitHub Actions:** Configured in `.github/workflows/`. Uses `${{ vars.VAR_NAME }}` for repository variables.\n-   **Google Cloud Build:** Configured in `.cloudbuild/`. Uses `${_VAR_NAME}` for substitution variables.\n\nWhen adding a new variable or secret, ensure it is configured correctly for both systems in the Terraform scripts that manage them (e.g., `github_actions_variable` resource and Cloud Build trigger substitutions).\n\n---\n\n## Terraform Best Practices\n\n### Unified Service Account (`app_sa`)\n\nThe project uses a single, unified application service account (`app_sa`) across all deployment targets to simplify IAM management.\n\n-   **Do not** create target-specific service accounts (e.g., `cloud_run_sa`)\n-   Define roles for this account in `app_sa_roles`\n-   Reference this account consistently in all Terraform and CI/CD files\n\n### Resource Referencing\n\nUse consistent and clear naming for Terraform resources. When referencing resources, especially those created conditionally or with `for_each`, ensure the reference is also correctly keyed.\n\n```hcl\n# Creation\nresource \"google_service_account\" \"app_sa\" {\n  for_each   = local.deploy_project_ids # e.g., {\"staging\" = \"...\", \"prod\" = \"...\"}\n  account_id = \"${var.project_name}-app\"\n  # ...\n}\n\n# Correct Reference\n# In a Cloud Run module for the staging environment\nservice_account = google_service_account.app_sa[\"staging\"].email\n```\n\n---\n\n## Pull Request Best Practices\n\n### Commit Message Format\n\n```\n<type>: <concise summary in imperative mood>\n\n<detailed explanation of the change>\n- Why the change was needed\n- What was the root cause\n- How the fix addresses it\n```\n\n**Types**: `fix`, `feat`, `refactor`, `docs`, `test`, `chore`\n\n### PR Structure Example\n\n**Title:** Brief, descriptive summary (50-60 chars)\n```\nFix Cloud Build service account permission for GitHub PAT secret access\n```\n\n**Description:**\n```markdown\n## Summary\n- Key change 1 (what was added/modified)\n- Key change 2\n- Key change 3\n\n## Problem\nClear description of the issue, including:\n- Error messages or symptoms\n- Why it was failing\n- Context about when/where it occurs\n\n## Solution\nExplanation of how the changes fix the problem:\n- What resources/files were modified\n- Why this approach was chosen\n- Any dependencies or sequencing requirements\n```\n\n### Example (based on actual PR)\n\n**Commit:**\n```\nFix Cloud Build service account permission for GitHub PAT secret access\n\nAdd IAM binding to grant Cloud Build service account the secretAccessor\nrole for the GitHub PAT secret. This resolves permission errors when\nTerraform creates Cloud Build v2 connections in E2E tests.\n\nThe CLI setup already grants this permission via gcloud, but the\nTerraform configuration was missing this binding, causing failures when\nTerraform runs independently.\n```\n\n**PR Description:**\n```markdown\n## Summary\n- Grant Cloud Build service account `secretmanager.secretAccessor` role\n- Add proper dependency to Cloud Build v2 connection resource\n\n## Problem\nE2E tests failed when Terraform attempted to create Cloud Build v2 connections:\n```\nError: could not access secret with service account:\ngeneric::permission_denied\n```\n\nThe CLI setup grants this permission via gcloud, but Terraform\nconfiguration lacked the IAM binding.\n\n## Solution\nAdded `google_secret_manager_secret_iam_member` resource to grant the\nCloud Build service account permission to access the GitHub PAT secret\nbefore creating the connection.\n```\n\n### Key Principles\n\n- **Concise but complete**: Provide enough context for reviewers\n- **Problem-first**: Explain the \"why\" before the \"what\"\n- **Professional tone**: Avoid mentions of AI tools or assistants\n\n---\n\n## File Modification Checklist\n\n-   [ ] **Jinja Syntax:** All `{% if %}` and `{% for %}` blocks correctly closed?\n-   [ ] **Variable Consistency:** `cookiecutter.` variables spelled correctly?\n-   [ ] **Cross-Target Impact:** Base template changes checked against deployment targets?\n-   [ ] **CI/CD Parity:** Changes applied to both GitHub Actions and Cloud Build?\n-   [ ] **Multi-Agent Testing:** Tested with different agent types and configurations?\n\n---\n\n## Quick Reference\n\n### Fast Project Creation\n\n```bash\n# Quick prototype project (no CI/CD, no Terraform, no prompts)\nuv run agent-starter-pack create mytest -p -s -y -d agent_engine --output-dir target\n\n# Flags explained:\n# -p / --prototype  : Minimal project (no CI/CD or Terraform)\n# -s / --skip-checks: Skip GCP/Vertex AI verification\n# -y / --auto-approve: Skip all confirmation prompts\n# -d : Deployment target\n# --output-dir target: Output to target/ (gitignored)\n```\n\n### Common Test Combinations\n\n```bash\n# Agent Engine + prototype (fastest)\nuv run agent-starter-pack create test-$(date +%s) -p -s -y -d agent_engine --output-dir target\n\n# Cloud Run with session type\nuv run agent-starter-pack create test-$(date +%s) -p -s -y -d cloud_run --session-type in_memory --output-dir target\n\n# GKE with session type\nuv run agent-starter-pack create test-$(date +%s) -p -s -y -d gke --session-type in_memory --output-dir target\n\n# Full project with CI/CD\nuv run agent-starter-pack create test-$(date +%s) -s -y -d agent_engine --cicd-runner google_cloud_build --output-dir target\n```\n\n### Key Files Reference\n\n| File | Purpose |\n|------|---------|\n| `agent_starter_pack/cli/commands/create.py` | Main create command, CLI flags, shared options |\n| `agent_starter_pack/cli/utils/template.py` | Template processing, `process_template()`, CI/CD runner prompt |\n| `agent_starter_pack/base_templates/python/pyproject.toml` | Generated project metadata, `[tool.agent-starter-pack]` section |\n| `agent_starter_pack/base_templates/python/Makefile` | Generated project Makefile targets |\n\n### Key Tooling\n\n-   **`uv` for Python:** Primary tool for dependency management and CLI execution\n\n---\n\n## Common Pitfalls\n\n- **Hardcoded URLs**: Use relative paths for frontend connections\n- **Missing Conditionals**: Wrap agent-specific code in proper `{% if %}` blocks\n- **Dependency Conflicts**: Some agents lack certain extras (e.g., adk_live + lint)\n- **makefile_hashes.json**: Can cause merge conflicts during active development - regenerate if needed\n\n---\n\n## Project Metadata Structure\n\nGenerated projects store creation context in `pyproject.toml`:\n\n```toml\n[tool.agent-starter-pack]\n# Metadata\nname = \"my-project\"\nbase_template = \"adk\"\nasp_version = \"0.25.0\"\n\n[tool.agent-starter-pack.create_params]\n# CLI params used during creation - used by enhance command\ndeployment_target = \"cloud_run\"\nsession_type = \"in_memory\"\ncicd_runner = \"skip\"\n```\n\nThe `create_params` section enables the `enhance` command to recreate identical scaffolding with the locked ASP version.\n"},"files":{"GEMINI.md":"# Agent Starter Pack - AI Coding Agent Guide\n\n> **Scope**: This document is for AI coding agents contributing to the **Agent Starter Pack repository itself** (the template generator). For guidance on working with **generated projects**, see [llm.txt](./llm.txt).\n\nThis document provides essential guidance, architectural insights, and best practices for AI coding agents tasked with modifying the Google Cloud Agent Starter Pack. Adhering to these principles is critical for making safe, consistent, and effective changes.\n\n---\n\n## Core Principles for AI Agents\n\n1.  **Preserve and Isolate:** Your primary objective is surgical precision. Modify *only* the code segments directly related to the user's request. Preserve all surrounding code, comments, and formatting. Do not rewrite entire files or functions to make a small change.\n2.  **Follow Conventions:** This project relies heavily on established patterns. Before writing new code, analyze the surrounding files to understand and replicate existing conventions for naming, templating logic, and directory structure.\n3.  **Template-First Mindset:** ASP is a template generator. The CLI should remain lean with good defaults. Most features belong in templates, not CLI code.\n4.  **Search Comprehensively:** A single change often requires updates in multiple places. When modifying configuration, variables, or infrastructure, you **must** search across the entire repository, including:\n    *   `agent_starter_pack/base_templates/` (core templates by language)\n    *   `agent_starter_pack/deployment_targets/` (environment-specific overrides)\n    *   `.github/` and `.cloudbuild/` (CI/CD workflows)\n    *   `docs/` (user-facing documentation)\n\n---\n\n## Project Architecture Overview\n\n### 4-Layer Template System\n\nTemplate processing follows this hierarchy (later layers override earlier ones):\n\n| Layer | Directory | Purpose |\n|-------|-----------|---------|\n| 1. Base | `agent_starter_pack/base_templates/<language>/` | Core Jinja scaffolding (Python, Go, more coming) |\n| 2. Deployment | `agent_starter_pack/deployment_targets/` | Environment overrides (cloud_run, gke, agent_engine) |\n| 3. Frontend | `agent_starter_pack/frontends/` | UI-specific files |\n| 4. Agent | `agent_starter_pack/agents/*/` | Agent-specific logic and configurations |\n\n**Rule**: Always place changes in the correct layer. Check if deployment targets need corresponding updates.\n\n### Key Directory Structure\n\n```\nagent_starter_pack/\n├── agents/                    # Agent-specific files\n│   ├── adk/                   # Base ADK agent (Python)\n│   ├── adk_a2a/               # A2A-enabled ADK agent\n│   ├── adk_go/                # Base ADK agent (Go)\n│   ├── adk_live/              # Real-time multimodal agent\n│   ├── agentic_rag/           # RAG agent\n│   └── langgraph/             # LangGraph-based agent\n├── base_templates/            # Core Jinja templates by language\n│   ├── python/                # Python project template\n│   │   ├── {{cookiecutter.agent_directory}}/\n│   │   ├── deployment/\n│   │   ├── tests/\n│   │   └── Makefile\n│   └── go/                    # Go project template\n├── deployment_targets/        # Environment-specific overrides\n│   ├── agent_engine/          # Agent Engine deployment\n│   ├── cloud_run/             # Cloud Run deployment\n│   └── gke/                   # GKE Autopilot deployment\n├── frontends/                 # UI templates\n└── cli/                       # CLI implementation\n    ├── commands/              # create, setup-cicd, enhance, etc.\n    └── utils/                 # Template processing, helpers\n```\n\n### When to Modify What\n\n| Change Type | Where to Modify | Also Check |\n|-------------|-----------------|------------|\n| Affects ALL generated projects | `base_templates/<language>/` | Deployment targets for conflicts |\n| Deployment-specific logic | `deployment_targets/<target>/` | Base templates for shared code |\n| Agent-specific feature | `agents/<agent>/` | Other agents for consistency |\n| New CLI flag/command | `cli/commands/` | `cli/utils/` for shared logic |\n| CI/CD changes | Both `.github/` AND `.cloudbuild/` | Keep in sync |\n| Documentation | `docs/` | README.md for overview changes |\n\n### Template Processing Flow\n\n1.  **Variable resolution** from `cookiecutter.json`\n2.  **File copying** (base → deployment → frontend → agent overlays)\n3.  **Jinja2 rendering** of file content\n4.  **File/directory name rendering** (Jinja in filenames)\n\n### Cross-File Dependencies\n\nChanges often require coordinated updates:\n- **Configuration**: `templateconfig.yaml` → `cookiecutter.json` → rendered templates\n- **CI/CD**: `.github/workflows/` ↔ `.cloudbuild/` (must stay in sync)\n- **Infrastructure**: Base terraform → deployment target overrides\n\n---\n\n## Template Development Workflow\n\nTemplate changes require a specific workflow because you're modifying Jinja templates, not regular source files.\n\n> **Note:** This workflow applies to both Python and Go templates. Both use Jinja templating with the same patterns (`{{cookiecutter.*}}`, `{% if %}`, etc.).\n\n### Step-by-Step Process\n\n#### 1. Generate a Test Instance\n\n```bash\nuv run agent-starter-pack create mytest -p -s -y -d cloud_run --output-dir target\n```\n\nFlags explained:\n- `-p` / `--prototype`: Minimal project (no CI/CD or Terraform)\n- `-s` / `--skip-checks`: Skip GCP/Vertex AI verification\n- `-y` / `--auto-approve`: Skip all confirmation prompts\n- `-d`: Deployment target\n- `--output-dir target`: Output to target/ (gitignored)\n\n#### 2. Initialize Git in the Generated Project\n\n```bash\ncd target/mytest && git init && git add . && git commit -m \"Initial\"\n```\n\nThis creates a baseline for tracking your changes with `git diff`.\n\n#### 3. Develop with Tight Feedback Loops\n\n- Make changes directly in `target/mytest/`\n- Test immediately: `make lint`, run the code, check output\n- Iterate until the change works correctly\n- Use `git diff` to see exactly what you changed\n\n#### 4. Backport Changes to Jinja Templates\n\n- Find the source template: `find agent_starter_pack -name \"filename.py\" -type f`\n- Apply your changes to the template file\n- Add Jinja conditionals if the change is conditional\n- Use `{%- -%}` whitespace control carefully\n\n#### 5. Validate Across Combinations\n\n```bash\n# Test your target combination\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# Test alternate agent with same deployment\n_TEST_AGENT_COMBINATION=\"adk_live,cloud_run\" make lint-templated-agents\n\n# Test same agent with alternate deployment\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n```\n\n### Why This Workflow?\n\n- Jinja templates are harder to debug than rendered code\n- Generated projects give immediate feedback on syntax errors\n- Backporting ensures you understand exactly what changed\n- Cross-combination testing catches conditional logic bugs\n\n### Language-Specific Notes\n\nThe template development workflow above applies to all languages. Here are language-specific details:\n\n| Language | Agent(s) | Linter | Test Command | Status |\n|----------|----------|--------|--------------|--------|\n| Python | adk, adk_a2a, adk_live, agentic_rag, langgraph, custom_a2a | `ruff`, `ty` | `make lint` | Production |\n| Go | adk_go | `golangci-lint` | `make lint` | Production |\n| Java | (coming soon) | - | - | In development |\n| TypeScript | (coming soon) | - | - | In development |\n\n**Python example:**\n```bash\nuv run agent-starter-pack create mytest -a adk -d cloud_run -p -s -y --output-dir target\n```\n\n**Go example:**\n```bash\nuv run agent-starter-pack create mytest -a adk_go -d cloud_run -p -s -y --output-dir target\n```\n\n---\n\n## Jinja Templating Rules\n\n> **Note:** These rules apply to both Python and Go templates. Both languages use the same Jinja2 templating patterns.\n\n### Templating Engine: Cookiecutter + Jinja2\n\nThe starter pack uses **Cookiecutter** to generate project scaffolding from templates customized with **Jinja2**. Understanding the rendering process is key to avoiding errors.\n\n**Multi-Phase Template Processing:**\n\n1.  **Cookiecutter Variable Substitution:** Replacement of `{{cookiecutter.variable_name}}` placeholders\n2.  **Jinja2 Logic Execution:** Conditional blocks (`{% if %}`), loops (`{% for %}`)\n3.  **File/Directory Name Templating:** Jinja2 in filenames is rendered\n\n### Block Balancing (Critical)\n\n**Every opening Jinja block must have a corresponding closing block.**\n\n-   `{% if ... %}` requires `{% endif %}`\n-   `{% for ... %}` requires `{% endfor %}`\n-   `{% raw %}` requires `{% endraw %}`\n\n```jinja\n{% if cookiecutter.deployment_target == 'cloud_run' %}\n  # Cloud Run specific content\n{% endif %}\n```\n\n### Variable Usage\n\nDistinguish between substitution and logic:\n\n-   **Substitution (in file content):** `{{ cookiecutter.project_name }}`\n-   **Logic (in `if`/`for` blocks):** `{% if cookiecutter.session_type == 'cloud_sql' %}`\n\n### Whitespace Control\n\nJinja is sensitive to whitespace. Use hyphens to control newlines:\n\n-   `{%-` removes whitespace before the block\n-   `-%}` removes whitespace after the block\n-   `{%- -%}` removes whitespace on both sides\n\n```jinja\n{%- if cookiecutter.some_option %}\noption = true\n{%- endif %}\n```\n\n### Conditional Logic Patterns\n\n```jinja\n{%- if cookiecutter.agent_name == \"adk_live\" %}\n# Agent-specific logic\n{%- elif cookiecutter.deployment_target == \"cloud_run\" %}\n# Deployment-specific logic\n{%- endif %}\n```\n\n---\n\n## Critical Whitespace Control Patterns\n\nJinja2 whitespace control is the #1 source of linting failures. Understanding these patterns is essential.\n\n### Pattern 1: Conditional Imports with Blank Line Separation\n\n**Problem:** Python requires blank lines to separate third-party imports from project imports. Conditional imports must handle this correctly.\n\n**Wrong - Creates extra blank line:**\n```jinja\nfrom opentelemetry.sdk.trace import TracerProvider, export\n{% if cookiecutter.session_type == \"agent_engine\" %}\nfrom vertexai import agent_engines\n{% endif %}\n\nfrom app.app_utils.gcs import create_bucket_if_not_exists\n```\n\n**Correct - Exactly one blank line:**\n```jinja\nfrom opentelemetry.sdk.trace import TracerProvider, export\n{% if cookiecutter.session_type == \"agent_engine\" -%}\nfrom vertexai import agent_engines\n{% endif %}\n\n{%- if cookiecutter.is_a2a %}\nfrom {{cookiecutter.agent_directory}}.agent import app as adk_app\n\n{% endif %}\nfrom {{cookiecutter.agent_directory}}.app_utils.gcs import create_bucket_if_not_exists\n```\n\n**Key points:**\n- Use `{%- -%}` to control BOTH sides when needed\n- The blank line AFTER the conditional import goes INSIDE the if block when needed\n- Test BOTH when condition is true AND false\n\n### Pattern 2: Long Import Lines\n\n**Problem:** Ruff enforces line length limits. Long import statements must be split.\n\n**Wrong - Too long:**\n```python\nfrom app.app_utils.typing import Feedback, InputChat, Request, dumps, ensure_valid_config\n```\n\n**Correct - Split with parentheses:**\n```python\nfrom app.app_utils.typing import (\n    Feedback,\n    InputChat,\n    Request,\n    dumps,\n    ensure_valid_config,\n)\n```\n\n### Pattern 3: File End Newlines\n\n**Problem:** Ruff requires exactly ONE newline at the end of every file.\n\n**Wrong - No newline:**\n```jinja\nagent_engine = AgentEngineApp(project_id=project_id)\n{%- endif %}\n```\n\n**Wrong - Extra newline:**\n```jinja\nagent_engine = AgentEngineApp(project_id=project_id)\n{%- endif %}\n\n```\n\n**Correct - Exactly one:**\n```jinja\nagent_engine = AgentEngineApp(project_id=project_id)\n{%- endif %}\n```\n\n**Key for nested conditionals:**\n```jinja\nagent_engine = AgentEngineApp(\n    app=adk_app,\n    artifact_service_builder=artifact_service_builder,\n)\n{%- endif -%}\n{% else %}\n\nimport logging\n```\n\nNotice `{%- endif -%}` to prevent blank line before the else block.\n\n### Whitespace Control Cheat Sheet\n\n```jinja\n# Remove whitespace BEFORE the tag\n{%- if condition %}\n\n# Remove whitespace AFTER the tag\n{% if condition -%}\n\n# Remove whitespace on BOTH sides\n{%- if condition -%}\n\n# Typical pattern for conditional imports\n{% if condition -%}\nimport something\n{% endif %}\n\n# Typical pattern for conditional code blocks with blank line before\n{%- if condition %}\n\nsome_code()\n{%- endif %}\n\n# Pattern for preventing blank line between consecutive conditionals\n{%- endif -%}\n{%- if next_condition %}\n```\n\n---\n\n## Testing Strategy\n\n### Testing Coverage Matrix\n\n**Critical Principle:** Template changes can affect MULTIPLE agent/deployment combinations. Test across combinations when making template modifications.\n\n| Dimension | Options |\n|-----------|---------|\n| Agents | adk, adk_a2a, adk_go, adk_live, agentic_rag, langgraph |\n| Deployments | cloud_run, gke, agent_engine |\n| Session types | in_memory, cloud_sql, agent_engine |\n| Features | data_ingestion, frontend_type |\n\n### Minimum Coverage Before PR\n\n- [ ] Your target combination\n- [ ] One alternate agent with same deployment target\n- [ ] One alternate deployment target with same agent\n\n### Linting Commands\n\n**IMPORTANT:** Only run linting when explicitly requested by the user. Do not proactively lint unless asked.\n\n```bash\n# Linting a specific combination\n_TEST_AGENT_COMBINATION=\"agent,target,--param,value\" make lint-templated-agents\n\n# Testing a specific combination\n_TEST_AGENT_COMBINATION=\"agent,target,--param,value\" make test-templated-agents\n```\n\n### Common Test Combinations\n\n```bash\n# Cloud Run combinations (Python)\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,in_memory\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk_live,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# Agent Engine combinations (Python)\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk_live,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"langgraph,agent_engine\" make lint-templated-agents\n\n# GKE combinations (Python)\n_TEST_AGENT_COMBINATION=\"adk,gke,--session-type,in_memory\" make lint-templated-agents\n\n# Go template testing\n_TEST_AGENT_COMBINATION=\"adk_go,cloud_run\" make lint-templated-agents\n\n# Go template testing (GKE)\n_TEST_AGENT_COMBINATION=\"adk_go,gke\" make lint-templated-agents\n\n# With session type variations\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,agent_engine\" make lint-templated-agents\n```\n\n### Testing Workflow for Template Changes\n\n**Before committing ANY template change:**\n\n```bash\n# 1. Test the specific combination you're working on\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# 2. Test related combinations (same deployment, different agents)\n_TEST_AGENT_COMBINATION=\"adk_live,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# 3. Test alternate code paths (different deployment, session types)\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n\n# 4. If modifying deployment target files, test all agents with that target\n# For agent_engine changes:\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk_live,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"langgraph,agent_engine\" make lint-templated-agents\n```\n\n**Golden Rule:** After ANY template change affecting imports, conditionals, or file endings, test AT LEAST 3 combinations:\n1. The target combination\n2. An alternate agent with same deployment\n3. An alternate deployment with same agent\n\n---\n\n## Debugging Linting Failures\n\n### Step 1: Identify the Exact Error\n\n```bash\n# Look for the diff output in the error message\n--- app/fast_api_app.py\n+++ app/fast_api_app.py\n@@ -21,6 +21,7 @@\n from opentelemetry import trace\n from vertexai import agent_engines\n+\n from app.app_utils.gcs import create_bucket_if_not_exists\n```\n\nThe `+` line shows what Ruff WANTS to add. In this case, it wants a blank line after `agent_engines`.\n\n### Step 2: Find the Generated File\n\n```bash\n# Generated files are in target/\ncat target/project-name/app/fast_api_app.py | head -30\n```\n\n### Step 3: Trace Back to Template\n\n```bash\n# Find the template source\nfind agent_starter_pack -name \"fast_api_app.py\" -type f\n```\n\n### Step 4: Check BOTH Branches of Conditionals\n\n- If `{% if condition %}` exists, test with condition true AND false\n- Use different agent combinations to toggle different conditions\n\n### Common Linting Errors and Fixes\n\n| Error | Cause | Fix |\n|-------|-------|-----|\n| Missing blank line between imports | Conditional import without proper spacing | Add blank line inside `{% if %}` block with correct `{%- -%}` control |\n| Extra blank line between imports | Jinja block creating unwanted newline | Use `{%- endif -%}` to strip both sides |\n| Missing newline at end of file | Template ends without final newline | Ensure template has exactly one blank line at end |\n| Extra blank line at end of file | Multiple newlines or `{% endif %}` creating extra line | Use `{%- endif -%}` pattern |\n| Line too long | Import statement exceeds limit | Split into multi-line with parentheses |\n\n### Files Most Prone to Linting Issues\n\n1. **`agent_engine_app.py`** (deployment_targets/agent_engine/)\n   - Multiple conditional paths (adk_live, adk_a2a, regular)\n   - End-of-file newline issues\n\n2. **`fast_api_app.py`** (deployment_targets/cloud_run/)\n   - Conditional imports (session_type, is_a2a)\n   - Long import lines\n   - Complex nested conditionals\n\n3. **Any file with `{% if cookiecutter.agent_name == \"...\" %}`**\n   - Different agents trigger different code paths\n   - Must test multiple agent types\n\n---\n\n## CI/CD Integration\n\nThe project maintains parallel CI/CD implementations. **Any change to CI/CD logic must be applied to both.**\n\n-   **GitHub Actions:** Configured in `.github/workflows/`. Uses `${{ vars.VAR_NAME }}` for repository variables.\n-   **Google Cloud Build:** Configured in `.cloudbuild/`. Uses `${_VAR_NAME}` for substitution variables.\n\nWhen adding a new variable or secret, ensure it is configured correctly for both systems in the Terraform scripts that manage them (e.g., `github_actions_variable` resource and Cloud Build trigger substitutions).\n\n---\n\n## Terraform Best Practices\n\n### Unified Service Account (`app_sa`)\n\nThe project uses a single, unified application service account (`app_sa`) across all deployment targets to simplify IAM management.\n\n-   **Do not** create target-specific service accounts (e.g., `cloud_run_sa`)\n-   Define roles for this account in `app_sa_roles`\n-   Reference this account consistently in all Terraform and CI/CD files\n\n### Resource Referencing\n\nUse consistent and clear naming for Terraform resources. When referencing resources, especially those created conditionally or with `for_each`, ensure the reference is also correctly keyed.\n\n```hcl\n# Creation\nresource \"google_service_account\" \"app_sa\" {\n  for_each   = local.deploy_project_ids # e.g., {\"staging\" = \"...\", \"prod\" = \"...\"}\n  account_id = \"${var.project_name}-app\"\n  # ...\n}\n\n# Correct Reference\n# In a Cloud Run module for the staging environment\nservice_account = google_service_account.app_sa[\"staging\"].email\n```\n\n---\n\n## Pull Request Best Practices\n\n### Commit Message Format\n\n```\n<type>: <concise summary in imperative mood>\n\n<detailed explanation of the change>\n- Why the change was needed\n- What was the root cause\n- How the fix addresses it\n```\n\n**Types**: `fix`, `feat`, `refactor`, `docs`, `test`, `chore`\n\n### PR Structure Example\n\n**Title:** Brief, descriptive summary (50-60 chars)\n```\nFix Cloud Build service account permission for GitHub PAT secret access\n```\n\n**Description:**\n```markdown\n## Summary\n- Key change 1 (what was added/modified)\n- Key change 2\n- Key change 3\n\n## Problem\nClear description of the issue, including:\n- Error messages or symptoms\n- Why it was failing\n- Context about when/where it occurs\n\n## Solution\nExplanation of how the changes fix the problem:\n- What resources/files were modified\n- Why this approach was chosen\n- Any dependencies or sequencing requirements\n```\n\n### Example (based on actual PR)\n\n**Commit:**\n```\nFix Cloud Build service account permission for GitHub PAT secret access\n\nAdd IAM binding to grant Cloud Build service account the secretAccessor\nrole for the GitHub PAT secret. This resolves permission errors when\nTerraform creates Cloud Build v2 connections in E2E tests.\n\nThe CLI setup already grants this permission via gcloud, but the\nTerraform configuration was missing this binding, causing failures when\nTerraform runs independently.\n```\n\n**PR Description:**\n```markdown\n## Summary\n- Grant Cloud Build service account `secretmanager.secretAccessor` role\n- Add proper dependency to Cloud Build v2 connection resource\n\n## Problem\nE2E tests failed when Terraform attempted to create Cloud Build v2 connections:\n```\nError: could not access secret with service account:\ngeneric::permission_denied\n```\n\nThe CLI setup grants this permission via gcloud, but Terraform\nconfiguration lacked the IAM binding.\n\n## Solution\nAdded `google_secret_manager_secret_iam_member` resource to grant the\nCloud Build service account permission to access the GitHub PAT secret\nbefore creating the connection.\n```\n\n### Key Principles\n\n- **Concise but complete**: Provide enough context for reviewers\n- **Problem-first**: Explain the \"why\" before the \"what\"\n- **Professional tone**: Avoid mentions of AI tools or assistants\n\n---\n\n## File Modification Checklist\n\n-   [ ] **Jinja Syntax:** All `{% if %}` and `{% for %}` blocks correctly closed?\n-   [ ] **Variable Consistency:** `cookiecutter.` variables spelled correctly?\n-   [ ] **Cross-Target Impact:** Base template changes checked against deployment targets?\n-   [ ] **CI/CD Parity:** Changes applied to both GitHub Actions and Cloud Build?\n-   [ ] **Multi-Agent Testing:** Tested with different agent types and configurations?\n\n---\n\n## Quick Reference\n\n### Fast Project Creation\n\n```bash\n# Quick prototype project (no CI/CD, no Terraform, no prompts)\nuv run agent-starter-pack create mytest -p -s -y -d agent_engine --output-dir target\n\n# Flags explained:\n# -p / --prototype  : Minimal project (no CI/CD or Terraform)\n# -s / --skip-checks: Skip GCP/Vertex AI verification\n# -y / --auto-approve: Skip all confirmation prompts\n# -d : Deployment target\n# --output-dir target: Output to target/ (gitignored)\n```\n\n### Common Test Combinations\n\n```bash\n# Agent Engine + prototype (fastest)\nuv run agent-starter-pack create test-$(date +%s) -p -s -y -d agent_engine --output-dir target\n\n# Cloud Run with session type\nuv run agent-starter-pack create test-$(date +%s) -p -s -y -d cloud_run --session-type in_memory --output-dir target\n\n# GKE with session type\nuv run agent-starter-pack create test-$(date +%s) -p -s -y -d gke --session-type in_memory --output-dir target\n\n# Full project with CI/CD\nuv run agent-starter-pack create test-$(date +%s) -s -y -d agent_engine --cicd-runner google_cloud_build --output-dir target\n```\n\n### Key Files Reference\n\n| File | Purpose |\n|------|---------|\n| `agent_starter_pack/cli/commands/create.py` | Main create command, CLI flags, shared options |\n| `agent_starter_pack/cli/utils/template.py` | Template processing, `process_template()`, CI/CD runner prompt |\n| `agent_starter_pack/base_templates/python/pyproject.toml` | Generated project metadata, `[tool.agent-starter-pack]` section |\n| `agent_starter_pack/base_templates/python/Makefile` | Generated project Makefile targets |\n\n### Key Tooling\n\n-   **`uv` for Python:** Primary tool for dependency management and CLI execution\n\n---\n\n## Common Pitfalls\n\n- **Hardcoded URLs**: Use relative paths for frontend connections\n- **Missing Conditionals**: Wrap agent-specific code in proper `{% if %}` blocks\n- **Dependency Conflicts**: Some agents lack certain extras (e.g., adk_live + lint)\n- **makefile_hashes.json**: Can cause merge conflicts during active development - regenerate if needed\n\n---\n\n## Project Metadata Structure\n\nGenerated projects store creation context in `pyproject.toml`:\n\n```toml\n[tool.agent-starter-pack]\n# Metadata\nname = \"my-project\"\nbase_template = \"adk\"\nasp_version = \"0.25.0\"\n\n[tool.agent-starter-pack.create_params]\n# CLI params used during creation - used by enhance command\ndeployment_target = \"cloud_run\"\nsession_type = \"in_memory\"\ncicd_runner = \"skip\"\n```\n\nThe `create_params` section enables the `enhance` command to recreate identical scaffolding with the locked ASP version.\n"},"items":[{"name":"GEMINI.md","path":"GEMINI.md","title":"GEMINI.md","content":"# Agent Starter Pack - AI Coding Agent Guide\n\n> **Scope**: This document is for AI coding agents contributing to the **Agent Starter Pack repository itself** (the template generator). For guidance on working with **generated projects**, see [llm.txt](./llm.txt).\n\nThis document provides essential guidance, architectural insights, and best practices for AI coding agents tasked with modifying the Google Cloud Agent Starter Pack. Adhering to these principles is critical for making safe, consistent, and effective changes.\n\n---\n\n## Core Principles for AI Agents\n\n1.  **Preserve and Isolate:** Your primary objective is surgical precision. Modify *only* the code segments directly related to the user's request. Preserve all surrounding code, comments, and formatting. Do not rewrite entire files or functions to make a small change.\n2.  **Follow Conventions:** This project relies heavily on established patterns. Before writing new code, analyze the surrounding files to understand and replicate existing conventions for naming, templating logic, and directory structure.\n3.  **Template-First Mindset:** ASP is a template generator. The CLI should remain lean with good defaults. Most features belong in templates, not CLI code.\n4.  **Search Comprehensively:** A single change often requires updates in multiple places. When modifying configuration, variables, or infrastructure, you **must** search across the entire repository, including:\n    *   `agent_starter_pack/base_templates/` (core templates by language)\n    *   `agent_starter_pack/deployment_targets/` (environment-specific overrides)\n    *   `.github/` and `.cloudbuild/` (CI/CD workflows)\n    *   `docs/` (user-facing documentation)\n\n---\n\n## Project Architecture Overview\n\n### 4-Layer Template System\n\nTemplate processing follows this hierarchy (later layers override earlier ones):\n\n| Layer | Directory | Purpose |\n|-------|-----------|---------|\n| 1. Base | `agent_starter_pack/base_templates/<language>/` | Core Jinja scaffolding (Python, Go, more coming) |\n| 2. Deployment | `agent_starter_pack/deployment_targets/` | Environment overrides (cloud_run, gke, agent_engine) |\n| 3. Frontend | `agent_starter_pack/frontends/` | UI-specific files |\n| 4. Agent | `agent_starter_pack/agents/*/` | Agent-specific logic and configurations |\n\n**Rule**: Always place changes in the correct layer. Check if deployment targets need corresponding updates.\n\n### Key Directory Structure\n\n```\nagent_starter_pack/\n├── agents/                    # Agent-specific files\n│   ├── adk/                   # Base ADK agent (Python)\n│   ├── adk_a2a/               # A2A-enabled ADK agent\n│   ├── adk_go/                # Base ADK agent (Go)\n│   ├── adk_live/              # Real-time multimodal agent\n│   ├── agentic_rag/           # RAG agent\n│   └── langgraph/             # LangGraph-based agent\n├── base_templates/            # Core Jinja templates by language\n│   ├── python/                # Python project template\n│   │   ├── {{cookiecutter.agent_directory}}/\n│   │   ├── deployment/\n│   │   ├── tests/\n│   │   └── Makefile\n│   └── go/                    # Go project template\n├── deployment_targets/        # Environment-specific overrides\n│   ├── agent_engine/          # Agent Engine deployment\n│   ├── cloud_run/             # Cloud Run deployment\n│   └── gke/                   # GKE Autopilot deployment\n├── frontends/                 # UI templates\n└── cli/                       # CLI implementation\n    ├── commands/              # create, setup-cicd, enhance, etc.\n    └── utils/                 # Template processing, helpers\n```\n\n### When to Modify What\n\n| Change Type | Where to Modify | Also Check |\n|-------------|-----------------|------------|\n| Affects ALL generated projects | `base_templates/<language>/` | Deployment targets for conflicts |\n| Deployment-specific logic | `deployment_targets/<target>/` | Base templates for shared code |\n| Agent-specific feature | `agents/<agent>/` | Other agents for consistency |\n| New CLI flag/command | `cli/commands/` | `cli/utils/` for shared logic |\n| CI/CD changes | Both `.github/` AND `.cloudbuild/` | Keep in sync |\n| Documentation | `docs/` | README.md for overview changes |\n\n### Template Processing Flow\n\n1.  **Variable resolution** from `cookiecutter.json`\n2.  **File copying** (base → deployment → frontend → agent overlays)\n3.  **Jinja2 rendering** of file content\n4.  **File/directory name rendering** (Jinja in filenames)\n\n### Cross-File Dependencies\n\nChanges often require coordinated updates:\n- **Configuration**: `templateconfig.yaml` → `cookiecutter.json` → rendered templates\n- **CI/CD**: `.github/workflows/` ↔ `.cloudbuild/` (must stay in sync)\n- **Infrastructure**: Base terraform → deployment target overrides\n\n---\n\n## Template Development Workflow\n\nTemplate changes require a specific workflow because you're modifying Jinja templates, not regular source files.\n\n> **Note:** This workflow applies to both Python and Go templates. Both use Jinja templating with the same patterns (`{{cookiecutter.*}}`, `{% if %}`, etc.).\n\n### Step-by-Step Process\n\n#### 1. Generate a Test Instance\n\n```bash\nuv run agent-starter-pack create mytest -p -s -y -d cloud_run --output-dir target\n```\n\nFlags explained:\n- `-p` / `--prototype`: Minimal project (no CI/CD or Terraform)\n- `-s` / `--skip-checks`: Skip GCP/Vertex AI verification\n- `-y` / `--auto-approve`: Skip all confirmation prompts\n- `-d`: Deployment target\n- `--output-dir target`: Output to target/ (gitignored)\n\n#### 2. Initialize Git in the Generated Project\n\n```bash\ncd target/mytest && git init && git add . && git commit -m \"Initial\"\n```\n\nThis creates a baseline for tracking your changes with `git diff`.\n\n#### 3. Develop with Tight Feedback Loops\n\n- Make changes directly in `target/mytest/`\n- Test immediately: `make lint`, run the code, check output\n- Iterate until the change works correctly\n- Use `git diff` to see exactly what you changed\n\n#### 4. Backport Changes to Jinja Templates\n\n- Find the source template: `find agent_starter_pack -name \"filename.py\" -type f`\n- Apply your changes to the template file\n- Add Jinja conditionals if the change is conditional\n- Use `{%- -%}` whitespace control carefully\n\n#### 5. Validate Across Combinations\n\n```bash\n# Test your target combination\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# Test alternate agent with same deployment\n_TEST_AGENT_COMBINATION=\"adk_live,cloud_run\" make lint-templated-agents\n\n# Test same agent with alternate deployment\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n```\n\n### Why This Workflow?\n\n- Jinja templates are harder to debug than rendered code\n- Generated projects give immediate feedback on syntax errors\n- Backporting ensures you understand exactly what changed\n- Cross-combination testing catches conditional logic bugs\n\n### Language-Specific Notes\n\nThe template development workflow above applies to all languages. Here are language-specific details:\n\n| Language | Agent(s) | Linter | Test Command | Status |\n|----------|----------|--------|--------------|--------|\n| Python | adk, adk_a2a, adk_live, agentic_rag, langgraph, custom_a2a | `ruff`, `ty` | `make lint` | Production |\n| Go | adk_go | `golangci-lint` | `make lint` | Production |\n| Java | (coming soon) | - | - | In development |\n| TypeScript | (coming soon) | - | - | In development |\n\n**Python example:**\n```bash\nuv run agent-starter-pack create mytest -a adk -d cloud_run -p -s -y --output-dir target\n```\n\n**Go example:**\n```bash\nuv run agent-starter-pack create mytest -a adk_go -d cloud_run -p -s -y --output-dir target\n```\n\n---\n\n## Jinja Templating Rules\n\n> **Note:** These rules apply to both Python and Go templates. Both languages use the same Jinja2 templating patterns.\n\n### Templating Engine: Cookiecutter + Jinja2\n\nThe starter pack uses **Cookiecutter** to generate project scaffolding from templates customized with **Jinja2**. Understanding the rendering process is key to avoiding errors.\n\n**Multi-Phase Template Processing:**\n\n1.  **Cookiecutter Variable Substitution:** Replacement of `{{cookiecutter.variable_name}}` placeholders\n2.  **Jinja2 Logic Execution:** Conditional blocks (`{% if %}`), loops (`{% for %}`)\n3.  **File/Directory Name Templating:** Jinja2 in filenames is rendered\n\n### Block Balancing (Critical)\n\n**Every opening Jinja block must have a corresponding closing block.**\n\n-   `{% if ... %}` requires `{% endif %}`\n-   `{% for ... %}` requires `{% endfor %}`\n-   `{% raw %}` requires `{% endraw %}`\n\n```jinja\n{% if cookiecutter.deployment_target == 'cloud_run' %}\n  # Cloud Run specific content\n{% endif %}\n```\n\n### Variable Usage\n\nDistinguish between substitution and logic:\n\n-   **Substitution (in file content):** `{{ cookiecutter.project_name }}`\n-   **Logic (in `if`/`for` blocks):** `{% if cookiecutter.session_type == 'cloud_sql' %}`\n\n### Whitespace Control\n\nJinja is sensitive to whitespace. Use hyphens to control newlines:\n\n-   `{%-` removes whitespace before the block\n-   `-%}` removes whitespace after the block\n-   `{%- -%}` removes whitespace on both sides\n\n```jinja\n{%- if cookiecutter.some_option %}\noption = true\n{%- endif %}\n```\n\n### Conditional Logic Patterns\n\n```jinja\n{%- if cookiecutter.agent_name == \"adk_live\" %}\n# Agent-specific logic\n{%- elif cookiecutter.deployment_target == \"cloud_run\" %}\n# Deployment-specific logic\n{%- endif %}\n```\n\n---\n\n## Critical Whitespace Control Patterns\n\nJinja2 whitespace control is the #1 source of linting failures. Understanding these patterns is essential.\n\n### Pattern 1: Conditional Imports with Blank Line Separation\n\n**Problem:** Python requires blank lines to separate third-party imports from project imports. Conditional imports must handle this correctly.\n\n**Wrong - Creates extra blank line:**\n```jinja\nfrom opentelemetry.sdk.trace import TracerProvider, export\n{% if cookiecutter.session_type == \"agent_engine\" %}\nfrom vertexai import agent_engines\n{% endif %}\n\nfrom app.app_utils.gcs import create_bucket_if_not_exists\n```\n\n**Correct - Exactly one blank line:**\n```jinja\nfrom opentelemetry.sdk.trace import TracerProvider, export\n{% if cookiecutter.session_type == \"agent_engine\" -%}\nfrom vertexai import agent_engines\n{% endif %}\n\n{%- if cookiecutter.is_a2a %}\nfrom {{cookiecutter.agent_directory}}.agent import app as adk_app\n\n{% endif %}\nfrom {{cookiecutter.agent_directory}}.app_utils.gcs import create_bucket_if_not_exists\n```\n\n**Key points:**\n- Use `{%- -%}` to control BOTH sides when needed\n- The blank line AFTER the conditional import goes INSIDE the if block when needed\n- Test BOTH when condition is true AND false\n\n### Pattern 2: Long Import Lines\n\n**Problem:** Ruff enforces line length limits. Long import statements must be split.\n\n**Wrong - Too long:**\n```python\nfrom app.app_utils.typing import Feedback, InputChat, Request, dumps, ensure_valid_config\n```\n\n**Correct - Split with parentheses:**\n```python\nfrom app.app_utils.typing import (\n    Feedback,\n    InputChat,\n    Request,\n    dumps,\n    ensure_valid_config,\n)\n```\n\n### Pattern 3: File End Newlines\n\n**Problem:** Ruff requires exactly ONE newline at the end of every file.\n\n**Wrong - No newline:**\n```jinja\nagent_engine = AgentEngineApp(project_id=project_id)\n{%- endif %}\n```\n\n**Wrong - Extra newline:**\n```jinja\nagent_engine = AgentEngineApp(project_id=project_id)\n{%- endif %}\n\n```\n\n**Correct - Exactly one:**\n```jinja\nagent_engine = AgentEngineApp(project_id=project_id)\n{%- endif %}\n```\n\n**Key for nested conditionals:**\n```jinja\nagent_engine = AgentEngineApp(\n    app=adk_app,\n    artifact_service_builder=artifact_service_builder,\n)\n{%- endif -%}\n{% else %}\n\nimport logging\n```\n\nNotice `{%- endif -%}` to prevent blank line before the else block.\n\n### Whitespace Control Cheat Sheet\n\n```jinja\n# Remove whitespace BEFORE the tag\n{%- if condition %}\n\n# Remove whitespace AFTER the tag\n{% if condition -%}\n\n# Remove whitespace on BOTH sides\n{%- if condition -%}\n\n# Typical pattern for conditional imports\n{% if condition -%}\nimport something\n{% endif %}\n\n# Typical pattern for conditional code blocks with blank line before\n{%- if condition %}\n\nsome_code()\n{%- endif %}\n\n# Pattern for preventing blank line between consecutive conditionals\n{%- endif -%}\n{%- if next_condition %}\n```\n\n---\n\n## Testing Strategy\n\n### Testing Coverage Matrix\n\n**Critical Principle:** Template changes can affect MULTIPLE agent/deployment combinations. Test across combinations when making template modifications.\n\n| Dimension | Options |\n|-----------|---------|\n| Agents | adk, adk_a2a, adk_go, adk_live, agentic_rag, langgraph |\n| Deployments | cloud_run, gke, agent_engine |\n| Session types | in_memory, cloud_sql, agent_engine |\n| Features | data_ingestion, frontend_type |\n\n### Minimum Coverage Before PR\n\n- [ ] Your target combination\n- [ ] One alternate agent with same deployment target\n- [ ] One alternate deployment target with same agent\n\n### Linting Commands\n\n**IMPORTANT:** Only run linting when explicitly requested by the user. Do not proactively lint unless asked.\n\n```bash\n# Linting a specific combination\n_TEST_AGENT_COMBINATION=\"agent,target,--param,value\" make lint-templated-agents\n\n# Testing a specific combination\n_TEST_AGENT_COMBINATION=\"agent,target,--param,value\" make test-templated-agents\n```\n\n### Common Test Combinations\n\n```bash\n# Cloud Run combinations (Python)\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,in_memory\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk_live,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# Agent Engine combinations (Python)\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk_live,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"langgraph,agent_engine\" make lint-templated-agents\n\n# GKE combinations (Python)\n_TEST_AGENT_COMBINATION=\"adk,gke,--session-type,in_memory\" make lint-templated-agents\n\n# Go template testing\n_TEST_AGENT_COMBINATION=\"adk_go,cloud_run\" make lint-templated-agents\n\n# Go template testing (GKE)\n_TEST_AGENT_COMBINATION=\"adk_go,gke\" make lint-templated-agents\n\n# With session type variations\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,agent_engine\" make lint-templated-agents\n```\n\n### Testing Workflow for Template Changes\n\n**Before committing ANY template change:**\n\n```bash\n# 1. Test the specific combination you're working on\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# 2. Test related combinations (same deployment, different agents)\n_TEST_AGENT_COMBINATION=\"adk_live,cloud_run,--session-type,in_memory\" make lint-templated-agents\n\n# 3. Test alternate code paths (different deployment, session types)\n_TEST_AGENT_COMBINATION=\"adk,cloud_run,--session-type,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n\n# 4. If modifying deployment target files, test all agents with that target\n# For agent_engine changes:\n_TEST_AGENT_COMBINATION=\"adk,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"adk_live,agent_engine\" make lint-templated-agents\n_TEST_AGENT_COMBINATION=\"langgraph,agent_engine\" make lint-templated-agents\n```\n\n**Golden Rule:** After ANY template change affecting imports, conditionals, or file endings, test AT LEAST 3 combinations:\n1. The target combination\n2. An alternate agent with same deployment\n3. An alternate deployment with same agent\n\n---\n\n## Debugging Linting Failures\n\n### Step 1: Identify the Exact Error\n\n```bash\n# Look for the diff output in the error message\n--- app/fast_api_app.py\n+++ app/fast_api_app.py\n@@ -21,6 +21,7 @@\n from opentelemetry import trace\n from vertexai import agent_engines\n+\n from app.app_utils.gcs import create_bucket_if_not_exists\n```\n\nThe `+` line shows what Ruff WANTS to add. In this case, it wants a blank line after `agent_engines`.\n\n### Step 2: Find the Generated File\n\n```bash\n# Generated files are in target/\ncat target/project-name/app/fast_api_app.py | head -30\n```\n\n### Step 3: Trace Back to Template\n\n```bash\n# Find the template source\nfind agent_starter_pack -name \"fast_api_app.py\" -type f\n```\n\n### Step 4: Check BOTH Branches of Conditionals\n\n- If `{% if condition %}` exists, test with condition true AND false\n- Use different agent combinations to toggle different conditions\n\n### Common Linting Errors and Fixes\n\n| Error | Cause | Fix |\n|-------|-------|-----|\n| Missing blank line between imports | Conditional import without proper spacing | Add blank line inside `{% if %}` block with correct `{%- -%}` control |\n| Extra blank line between imports | Jinja block creating unwanted newline | Use `{%- endif -%}` to strip both sides |\n| Missing newline at end of file | Template ends without final newline | Ensure template has exactly one blank line at end |\n| Extra blank line at end of file | Multiple newlines or `{% endif %}` creating extra line | Use `{%- endif -%}` pattern |\n| Line too long | Import statement exceeds limit | Split into multi-line with parentheses |\n\n### Files Most Prone to Linting Issues\n\n1. **`agent_engine_app.py`** (deployment_targets/agent_engine/)\n   - Multiple conditional paths (adk_live, adk_a2a, regular)\n   - End-of-file newline issues\n\n2. **`fast_api_app.py`** (deployment_targets/cloud_run/)\n   - Conditional imports (session_type, is_a2a)\n   - Long import lines\n   - Complex nested conditionals\n\n3. **Any file with `{% if cookiecutter.agent_name == \"...\" %}`**\n   - Different agents trigger different code paths\n   - Must test multiple agent types\n\n---\n\n## CI/CD Integration\n\nThe project maintains parallel CI/CD implementations. **Any change to CI/CD logic must be applied to both.**\n\n-   **GitHub Actions:** Configured in `.github/workflows/`. Uses `${{ vars.VAR_NAME }}` for repository variables.\n-   **Google Cloud Build:** Configured in `.cloudbuild/`. Uses `${_VAR_NAME}` for substitution variables.\n\nWhen adding a new variable or secret, ensure it is configured correctly for both systems in the Terraform scripts that manage them (e.g., `github_actions_variable` resource and Cloud Build trigger substitutions).\n\n---\n\n## Terraform Best Practices\n\n### Unified Service Account (`app_sa`)\n\nThe project uses a single, unified application service account (`app_sa`) across all deployment targets to simplify IAM management.\n\n-   **Do not** create target-specific service accounts (e.g., `cloud_run_sa`)\n-   Define roles for this account in `app_sa_roles`\n-   Reference this account consistently in all Terraform and CI/CD files\n\n### Resource Referencing\n\nUse consistent and clear naming for Terraform resources. When referencing resources, especially those created conditionally or with `for_each`, ensure the reference is also correctly keyed.\n\n```hcl\n# Creation\nresource \"google_service_account\" \"app_sa\" {\n  for_each   = local.deploy_project_ids # e.g., {\"staging\" = \"...\", \"prod\" = \"...\"}\n  account_id = \"${var.project_name}-app\"\n  # ...\n}\n\n# Correct Reference\n# In a Cloud Run module for the staging environment\nservice_account = google_service_account.app_sa[\"staging\"].email\n```\n\n---\n\n## Pull Request Best Practices\n\n### Commit Message Format\n\n```\n<type>: <concise summary in imperative mood>\n\n<detailed explanation of the change>\n- Why the change was needed\n- What was the root cause\n- How the fix addresses it\n```\n\n**Types**: `fix`, `feat`, `refactor`, `docs`, `test`, `chore`\n\n### PR Structure Example\n\n**Title:** Brief, descriptive summary (50-60 chars)\n```\nFix Cloud Build service account permission for GitHub PAT secret access\n```\n\n**Description:**\n```markdown\n## Summary\n- Key change 1 (what was added/modified)\n- Key change 2\n- Key change 3\n\n## Problem\nClear description of the issue, including:\n- Error messages or symptoms\n- Why it was failing\n- Context about when/where it occurs\n\n## Solution\nExplanation of how the changes fix the problem:\n- What resources/files were modified\n- Why this approach was chosen\n- Any dependencies or sequencing requirements\n```\n\n### Example (based on actual PR)\n\n**Commit:**\n```\nFix Cloud Build service account permission for GitHub PAT secret access\n\nAdd IAM binding to grant Cloud Build service account the secretAccessor\nrole for the GitHub PAT secret. This resolves permission errors when\nTerraform creates Cloud Build v2 connections in E2E tests.\n\nThe CLI setup already grants this permission via gcloud, but the\nTerraform configuration was missing this binding, causing failures when\nTerraform runs independently.\n```\n\n**PR Description:**\n```markdown\n## Summary\n- Grant Cloud Build service account `secretmanager.secretAccessor` role\n- Add proper dependency to Cloud Build v2 connection resource\n\n## Problem\nE2E tests failed when Terraform attempted to create Cloud Build v2 connections:\n```\nError: could not access secret with service account:\ngeneric::permission_denied\n```\n\nThe CLI setup grants this permission via gcloud, but Terraform\nconfiguration lacked the IAM binding.\n\n## Solution\nAdded `google_secret_manager_secret_iam_member` resource to grant the\nCloud Build service account permission to access the GitHub PAT secret\nbefore creating the connection.\n```\n\n### Key Principles\n\n- **Concise but complete**: Provide enough context for reviewers\n- **Problem-first**: Explain the \"why\" before the \"what\"\n- **Professional tone**: Avoid mentions of AI tools or assistants\n\n---\n\n## File Modification Checklist\n\n-   [ ] **Jinja Syntax:** All `{% if %}` and `{% for %}` blocks correctly closed?\n-   [ ] **Variable Consistency:** `cookiecutter.` variables spelled correctly?\n-   [ ] **Cross-Target Impact:** Base template changes checked against deployment targets?\n-   [ ] **CI/CD Parity:** Changes applied to both GitHub Actions and Cloud Build?\n-   [ ] **Multi-Agent Testing:** Tested with different agent types and configurations?\n\n---\n\n## Quick Reference\n\n### Fast Project Creation\n\n```bash\n# Quick prototype project (no CI/CD, no Terraform, no prompts)\nuv run agent-starter-pack create mytest -p -s -y -d agent_engine --output-dir target\n\n# Flags explained:\n# -p / --prototype  : Minimal project (no CI/CD or Terraform)\n# -s / --skip-checks: Skip GCP/Vertex AI verification\n# -y / --auto-approve: Skip all confirmation prompts\n# -d : Deployment target\n# --output-dir target: Output to target/ (gitignored)\n```\n\n### Common Test Combinations\n\n```bash\n# Agent Engine + prototype (fastest)\nuv run agent-starter-pack create test-$(date +%s) -p -s -y -d agent_engine --output-dir target\n\n# Cloud Run with session type\nuv run agent-starter-pack create test-$(date +%s) -p -s -y -d cloud_run --session-type in_memory --output-dir target\n\n# GKE with session type\nuv run agent-starter-pack create test-$(date +%s) -p -s -y -d gke --session-type in_memory --output-dir target\n\n# Full project with CI/CD\nuv run agent-starter-pack create test-$(date +%s) -s -y -d agent_engine --cicd-runner google_cloud_build --output-dir target\n```\n\n### Key Files Reference\n\n| File | Purpose |\n|------|---------|\n| `agent_starter_pack/cli/commands/create.py` | Main create command, CLI flags, shared options |\n| `agent_starter_pack/cli/utils/template.py` | Template processing, `process_template()`, CI/CD runner prompt |\n| `agent_starter_pack/base_templates/python/pyproject.toml` | Generated project metadata, `[tool.agent-starter-pack]` section |\n| `agent_starter_pack/base_templates/python/Makefile` | Generated project Makefile targets |\n\n### Key Tooling\n\n-   **`uv` for Python:** Primary tool for dependency management and CLI execution\n\n---\n\n## Common Pitfalls\n\n- **Hardcoded URLs**: Use relative paths for frontend connections\n- **Missing Conditionals**: Wrap agent-specific code in proper `{% if %}` blocks\n- **Dependency Conflicts**: Some agents lack certain extras (e.g., adk_live + lint)\n- **makefile_hashes.json**: Can cause merge conflicts during active development - regenerate if needed\n\n---\n\n## Project Metadata Structure\n\nGenerated projects store creation context in `pyproject.toml`:\n\n```toml\n[tool.agent-starter-pack]\n# Metadata\nname = \"my-project\"\nbase_template = \"adk\"\nasp_version = \"0.25.0\"\n\n[tool.agent-starter-pack.create_params]\n# CLI params used during creation - used by enhance command\ndeployment_target = \"cloud_run\"\nsession_type = \"in_memory\"\ncicd_runner = \"skip\"\n```\n\nThe `create_params` section enables the `enhance` command to recreate identical scaffolding with the locked ASP version.\n","category":"root","tokens":6092}]}