---
name: github-repository
description: Creates or updates a GitHub repository configuration in the terraform-infra monorepo using the terraform-github module. Use this skill when the user asks to "create a github repo", "create a new github repository", "update a github repo", "update github repository settings", "set up a github repository in terraform", or similar phrases. The trigger phrase must include either "github repo" or "github repository" to distinguish from other repository types. This skill handles fetching the latest module version, validating team slugs, gathering required inputs, and generating or updating the proper Terraform file structure.
---

# GitHub Repository in terraform-infra

This skill creates or updates a GitHub repository configuration in the terraform-infra monorepo using the theorchard/terraform-github module.

## Prerequisites

You must be working in the terraform-infra repository with access to:
- GitHub access via one of: GitHub MCP tools, `gh` CLI, or direct API access
- The `terraform` CLI (for formatting)
- Write access to the repository filesystem

## Workflow

### Step 1: Parse user intent and extract explicit details

Extract any explicitly provided information from the user's prompt:
- **Repository name**: Look for phrases like "create repo called X", "repo named X", "X repository", "update repo X"
- **Description**: Look for "description: X", "for X purpose", or similar context
- **Team/code owner**: Look for "for the X team", "owned by X", team mentions
- **Application family**: Sometimes mentioned alongside team or in context
- **GitHub organization**: Look for "in the organization X", "in the X org", "under X organization". If specified, use that value for `github_organization`; otherwise use the default `"theorchard"`

**Library repository detection**: Flag for follow-up questions in Step 5 if either:
- The user describes it as a library, package, or SDK, or
- The repository name starts with a language prefix: `python-`, `php-`, `ruby-`, `go-`, `java-`, `node-`, `js-`, `ts-`, `rust-`, `scala-`, `kotlin-`, `swift-`, or similar

Also note whether the repository name specifically starts with `python-`, as this affects a separate config option.

Don't make assumptions about data that isn't explicitly stated. You'll gather missing information in the next steps.

### Step 2: Check for directory conflicts

Check if the target directory already exists:

```bash
ls -la /path/to/terraform-infra/prod/github/${repository_name}/
```

**If the directory exists and contains Terraform files (*.tf):**
- This is an **update** — set `IS_UPDATE=true`
- Read the existing `main.tf` and `variables.tf` to understand the current configuration
- Inform the user: "Found existing Terraform configuration for ${repository_name}. Proceeding to update it."
- Continue to Step 3 — you will modify the existing files in Steps 7–8 rather than creating new ones

**If the directory does not exist or contains no .tf files:**
- This is a **create** — set `IS_UPDATE=false`
- Proceed normally

### Step 3: Fetch latest module version

**If `IS_UPDATE=true`:** Skip this step unless the user explicitly asked to upgrade the module version (e.g., "bump the module", "use the latest module version"). If skipped, preserve the existing `?ref=` value from the current `main.tf`.

Fetch the latest release tag from the `theorchard/terraform-github` repository. If no method is available, fall back to a recent known version (e.g., 6.1.2) and inform the user.

Extract the version tag (e.g., "6.1.2") from the output.

### Step 4: Fetch and validate Github team slug (if needed)

If the user didn't explicitly specify a team in their prompt, you need to fetch the allowed list and ask them to choose.

Fetch `variables.tf` from the `theorchard/terraform-github` repository and extract the `allowed_code_owner_teams` list from the `locals` block. This list defines which team slugs are valid. If no method is available, present common teams as a fallback: devops-squad, data-platform, insights, abacus, content-creation-management-ccm, etc.

If the user **did** specify a team explicitly in their prompt, trust their input and use it directly (don't validate upfront - Terraform will catch errors).

If the user **didn't** specify a team, use `AskUserQuestion` to let them select from the allowed list. Present the most commonly used teams as options and allow "Other" for less common teams.

### Step 5: Gather remaining required inputs

**If `IS_UPDATE=true`:** Do not re-ask for inputs that are already present in the existing configuration. Only use `AskUserQuestion` if the user's requested change is ambiguous or incomplete (e.g., they said "add the insights team" but it's unclear whether they mean `github_pull_teams` or `github_triage_teams`). Skip the required-inputs prompts below entirely and proceed with the changes the user specified.

**If `IS_UPDATE=false`:** Use `AskUserQuestion` to gather any missing required information:

**Required inputs (create only):**
- **repository_name** (extracted or asked)
- **description** (extracted or asked)
- **default_code_owner** (validated team slug)
- **application_family** (usually matches the team/domain context)

**Example AskUserQuestion structure:**

```
Question: "What should the repository description be?"
Options:
  - Provide 2-3 contextual suggestions based on repo name
  - "Other" option for custom input

Question: "What application family should this repository belong to?"
Options:
  - Suggest based on team (e.g., if team is "devops-squad", suggest "devops")
  - Common options: accounting, data-platform, devops, insights, etc.
  - "Other" option
```

**Library repositories**: If the repository was flagged in Step 1 (language-prefixed name or user described it as a library/package/SDK) and the user has not already confirmed, use `AskUserQuestion`:

```
Question: "Is this a library/package repository?"
Options:
  - Yes — this is a library or package
  - No — it is an application or service
```

If the answer is **Yes** (it is a library), ask a follow-up:

```
Question: "Does this repository use GitHub Actions for its CI pipeline (rather than Jenkins)?"
Options:
  - Yes — GitHub Actions
  - No — Jenkins or another system
```

If the answer is **Yes** (GitHub Actions), set `required_status_checks = []`. This removes the default Jenkins check, which would otherwise block merges.

If the repository is **both** a confirmed library **and** its name starts with `python-`, additionally set `pull_request_bypassers = ["orchardci"]`. This allows the CI bot to merge automated dependency or release PRs without a human review.

**Optional inputs** — extract from user prompt if mentioned, otherwise omit (module defaults apply):

| Variable | Default | When to ask/include |
|---|---|---|
| `branch_protection_enabled` | `true` | Include only if user says "no branch protection" or similar |
| `default_branch_name` | `"master"` | Include if user specifies `"main"` or another branch name |
| `github_code_owner_reviews` | `false` | Include if user wants code owner review enforcement |
| `required_approving_review_count` | `null` | Include if user specifies a number of required reviewers |
| `github_pull_teams` | `[]` | Include if user specifies additional teams needing pull access |
| `github_push_teams` | `["mergers"]` | Include only if user wants to override the default push teams |
| `github_triage_teams` | `["orcharddevs-ro"]` | Include only if user wants to override the default triage teams |
| `github_repository_pull_collaborators` | `[]` | Include if user specifies external collaborators (pull) |
| `github_repository_push_collaborators` | `[]` | Include if user specifies external collaborators (push) |
| `allow_merge_commit` | `false` | Include if user explicitly wants merge commits enabled |
| `allow_rebase_merge` | `false` | Include if user explicitly wants rebase merges enabled |
| `allow_squash_merge` | `true` | Include only if user wants to disable squash merges |
| `delete_branch_on_merge` | `true` | Include only if user wants to keep branches after merge |
| `dismiss_stale_reviews` | `true` | Include only if user wants to disable stale review dismissal |
| `require_last_push_approval` | `true` | Include only if user wants to disable this |
| `allows_force_pushes` | `false` | Include only if user explicitly needs force pushes |
| `pull_request_bypassers` | `[]` | Include if user specifies users who can bypass PR reviews |
| `required_status_checks` | `["Jenkins"]` | Include only if user wants to change or add status checks |
| `branch_protection_patterns` | `null` | Include if user wants to protect additional branch patterns |
| `autolink_references` | `[]` | Include if user wants Jira/Linear autolinks (see format below) |
| `archived_repository` | `false` | Include only if explicitly archiving |
| `homepage_url` | `null` | Include if user provides a URL |

**Autolink reference format** (when user mentions Jira, Linear, or similar):
```hcl
autolink_references = [
  {
    key_prefix          = "SYS-"
    target_url_template = "https://jira.example.com/browse/SYS-<num>"
    is_alphanumeric     = true
  }
]
```

**Only include optional variables in the generated files if their value differs from the module default.** This keeps the Terraform files minimal and readable.

### Step 6: Get latest Terraform version

**If `IS_UPDATE=true`:** Skip this step unless the user explicitly asked to upgrade the Terraform version. If skipped, preserve the existing `required_version` value from the current `versions.tf`.

Fetch the latest generally available Terraform version from HashiCorp's releases index:

```bash
curl -s https://releases.hashicorp.com/terraform/ \
  | grep -oP '(?<=terraform/)\d+\.\d+\.\d+(?=/)' \
  | grep -v -E '(alpha|beta|rc)' \
  | sort -V \
  | tail -1
```

Use the version string returned (e.g. `1.12.2`). Only use stable GA releases — exclude any version containing `alpha`, `beta`, or `rc`.


### Step 7: Create or update directory structure

**If `IS_UPDATE=false` (create):**
```bash
mkdir -p /path/to/terraform-infra/prod/github/${repository_name}
```

**If `IS_UPDATE=true` (update):**
The directory already exists — no action needed here. Existing files will be overwritten in Step 8.

### Step 8: Generate or update Terraform files

**If `IS_UPDATE=false` (create):** Generate all three files from scratch as described below.

**If `IS_UPDATE=true` (update):** Before applying the user's requested changes, check whether `main.tf` already contains a `provider "github"` block and whether `variables.tf` already declares `github_organization`. Add whichever are missing (see the create templates below for the exact content). Then make only the surgical edits the user requested. Do not regenerate or overwrite the files wholesale — edit only the specific lines that need to change. Three types of edits are possible:

- **Modify** an existing argument: change the value of a line already present in the module block (e.g., update `description` or `default_code_owner`)
- **Add** a new argument: insert a new line into the module block for an option not currently present (maintain column alignment with existing arguments)
- **Remove** an argument: delete the line for an option the user wants to revert to its module default

After all edits, re-align the `=` signs in the module block if the column width changed.

---

#### main.tf (create)

```hcl
provider "aws" {
  region = var.aws_region
}

provider "github" {
  organization = var.github_organization
  app_auth {}
}

# Terraform backends cannot contain interpolations
terraform {
  backend "s3" {
    bucket  = "orcd-terraform-state"
    key     = "prod/github/${repository_name}/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

module "github_repository" {
  source = "git@github.com:theorchard/terraform-github.git//?ref=${module_version}"

  repository_name    = "${repository_name}"
  description        = "${description}"
  default_code_owner = "${default_code_owner}"
  application_family = var.application_family
}
```

**Important notes:**
- Use the module version from Step 3
- The S3 key path must match the directory structure
- Do NOT include `branch_protection_enabled` - it defaults to `true`
- Align the equals signs for readability

#### variables.tf (create)

```hcl
variable "aws_region" {
  default = "us-east-1"
}

variable "github_organization" {
  default = "${github_organization}"  # "theorchard" unless the user specified otherwise in Step 1
}

variable "application_family" {
  default = "${application_family}"
}
```

#### versions.tf (create)

```hcl
terraform {
  required_version = "${terraform_version}"
  required_providers {
    github = {
      source = "integrations/github"
    }
  }
}
```

Use the latest Terraform version from Step 6.

**Why `required_providers` is required here:** The `provider "github" { app_auth {} }` block in `main.tf` must be explicitly associated with the `integrations/github` source. Without this declaration, Terraform cannot match the root module's provider configuration to the child module's `integrations/github` requirement — it treats them as different providers, instantiates a fresh unconfigured provider for the module, and the `app_auth` credentials are never passed through, causing 401 authentication errors at plan time.

The version is intentionally omitted — the `terraform-github` module declares its own version constraint, and Terraform will satisfy it automatically. Specifying a version here risks constraining to a release the module does not support.

### Step 9: Format the files

Run Terraform format on the files:

```bash
cd /path/to/terraform-infra/prod/github/${repository_name} && terraform fmt
```

### Step 10: Confirm completion

**If `IS_UPDATE=false` (create):**
```
Created GitHub repository configuration for ${repository_name}:
- Location: prod/github/${repository_name}/
- Module version: ${module_version}
- Terraform version: ${terraform_version}
- Files created: main.tf, variables.tf, versions.tf
```

**If `IS_UPDATE=true` (update):** Report only what changed, for example:
```
Updated GitHub repository configuration for ${repository_name}:
- Location: prod/github/${repository_name}/
- Changes applied:
    Added:    required_approving_review_count = 2
    Modified: description = "new description"
    Removed:  allows_force_pushes
```

## Example Usage

**User**: "Create a github repo called data-validation-scripts for the data platform team"

**Skill extracts:**
- repository_name: "data-validation-scripts"
- default_code_owner: "data-platform" (explicit)
- Team validation: Skip (user explicitly specified)

**Skill asks for:**
- Description (suggests options based on repo name)
- Application family (suggests "data-platform" based on team)

**Result:**
```
prod/github/data-validation-scripts/
├── main.tf
├── variables.tf
└── versions.tf
```

---

**User**: "Update the github repo frontend-workstation to require 2 approving reviewers"

**Skill detects:**
- IS_UPDATE=true (directory already exists with .tf files)
- required_approving_review_count: 2 (explicit)

**Skill reads existing config, applies the change, and reports:**
```
Updated GitHub repository configuration for frontend-workstation
```

## Common Patterns

### Repository naming conventions
- Use lowercase with hyphens: `my-repo-name`
- Avoid underscores, spaces, or special characters
- Be descriptive but concise

### Team to application family mapping
Common mappings (but always confirm with user):
- devops-squad → devops
- data-platform → data-platform
- insights → insights
- abacus → accounting
- content-creation-management-ccm → content-creation-management

### When users are unsure about inputs
If a user says they don't know what application family to use, suggest matching the team name or ask what domain/product area the repository serves.

## Error Handling

**Invalid team slug:**
- If Terraform validation fails later, explain that the team must be from the allowed list
- Provide a link to check: theorchard/terraform-github/blob/master/variables.tf

**Module version unavailable:**
- Fall back to a recent known version (check existing repos)
- Inform user which version was used

**Terraform CLI not available:**
- Skip formatting step
- Inform user to run `terraform fmt` manually after setup
