# SKILL: GitHub Organization Repository Template --- ## RESOLVED CONFIGURATION Three blocking variables are now confirmed. Update the remaining `{{ }}` placeholders (ORG_NAME, TEMPLATE_REPO, PRIMARY_CONTACT, AI_BOT_ACCOUNT, CITY_PROJECT_ID, DEFAULT_BRANCH, LICENSE_TYPE) before deploying. | Variable | Status | Resolved Value | Notes | |---|---|---|---| | `{{ ORG_TIER }}` | ✅ Resolved | `team` | GitHub Team plan. No GHAS — see plan implications below. | | `{{ AI_AUTH_TYPE }}` | ✅ Resolved | `fine-grained-pat` | Repo-scoped, expiring. **Cannot access GitHub Packages** — see AB-010. | | `{{ MIGRATION_ORIGIN }}` | ✅ Resolved | Per-repo (mixed) | Default template value: `fresh`. Override in each migrating repo's `repo-config.yml`. | | `{{ ORG_NAME }}` | ⏳ Set this | — | Your GitHub org slug | | `{{ TEMPLATE_REPO }}` | ⏳ Set this | — | Name of the template repo | | `{{ PRIMARY_CONTACT }}` | ⏳ Set this | — | Org owner GitHub username | | `{{ AI_BOT_ACCOUNT }}` | ⏳ Set this | — | GitHub account name for AI agents | | `{{ CITY_PROJECT_ID }}` | ⏳ Set this | — | Project slug, e.g. `ncz-2026` | | `{{ DEFAULT_BRANCH }}` | ⏳ Set this | `main` (recommended) | Default branch name | | `{{ LICENSE_TYPE }}` | ⏳ Set this | — | `MIT`, `Apache-2.0`, etc. | ### GitHub Team Plan — What This Means GitHub Team provides protected branches on private repos, more Actions minutes, and draft PRs. It does **not** include GitHub Advanced Security (GHAS). This has direct consequences for security feature availability: | Feature | Public repos | Private repos (Team, no GHAS) | |---|---|---| | Secret scanning (partner patterns) | ✅ Auto-enabled | ❌ Not available | | Secret scanning alerts | ✅ | ❌ Needs GHAS | | Push protection | ✅ | ❌ Needs GHAS | | Code scanning (CodeQL) | ✅ | ❌ Needs GHAS | | Dependency graph | ✅ | ✅ | | Dependabot alerts | ✅ | ✅ | | Dependabot security updates | ✅ | ✅ | | Branch protection rules | ✅ | ✅ (Team plan unlocks for private) | | GitHub Actions | ✅ | ✅ | **Practical consequence:** Design the org so that all repositories intended to be scanned are **public**. Private repos in this org should hold only: - Infrastructure secrets (handled through GitHub Secrets, not code) - Proprietary city planning data that must remain non-public AI-exclusive repos can be private — their security posture depends on access control (who can read the repo) rather than code scanning, since they hold schemas and data, not application code with vulnerabilities. ### Fine-Grained PAT — What This Means for AI Agents Fine-grained PATs are the correct choice for AI agents: they expire, they're repo-scoped, and they're auditable. One critical gap: > ⚠️ **Fine-grained PATs cannot authenticate to GitHub Packages** (PKG-001 in SKILL-010). > If any AI agent workflow needs to pull or push container images or npm packages > from `ghcr.io` or `npm.pkg.github.com`, it requires a **separate classic PAT** > with `read:packages` or `write:packages` scope stored as a secret. > This is a known GitHub limitation, not a configuration error. > See **AB-010** in the Known Gaps section below. Recommended fine-grained PAT permissions for AI agents (set when creating the PAT): ``` Repository permissions (on specific repos, not all): Contents: Read and write ← commit, push, read files Issues: Read and write ← create/update issues Pull requests: Read and write ← open/merge PRs Metadata: Read only ← always required, auto-selected Workflows: Read and write ← only if agent triggers workflows Repository permissions (read-only for schema validation): Contents: Read only ← for repos agent only reads ``` --- ## CONFIGURE BEFORE USE Replace the remaining `{{ }}` placeholders before deploying. | Variable | Description | Example | Blocking? | |---|---|---|---| | `{{ ORG_NAME }}` | GitHub organization slug | `new-city-project` | Yes | | `{{ ORG_TIER }}` | GitHub product tier | ~~`team`~~ **→ resolved: `team`** | Resolved | | `{{ TEMPLATE_REPO }}` | Name of the template repo itself | `org-repo-template` | Yes | | `{{ PRIMARY_CONTACT }}` | Org owner GitHub username (no @) | `albertlane` | Yes | | `{{ AI_BOT_ACCOUNT }}` | GitHub account name for AI agents | `city-ai-agent` | Yes | | `{{ AI_AUTH_TYPE }}` | How AI agents authenticate | ~~`fine-grained-pat`~~ **→ resolved: `fine-grained-pat`** | Resolved | | `{{ CITY_PROJECT_ID }}` | Unique project identifier | `ncz-2026` | No — use any slug | | `{{ DEFAULT_BRANCH }}` | Default branch name | `main` | No | | `{{ LICENSE_TYPE }}` | License for public repos | `MIT`, `Apache-2.0`, `CC-BY-4.0` | No | | `{{ MIGRATION_ORIGIN }}` | Where repos come from | ~~`mixed`~~ **→ per-repo, default `fresh`** | Per-repo | --- ## When Claude Uses This Skill Use this skill when asked to: - Create a new repository in `{{ ORG_NAME }}` - Generate or configure the organization's template repository - Set up a repo for AI-exclusive use - Configure a migration-ready repository structure - Produce a post-generation configuration checklist - Help another organization fork and adapt this template system Do NOT use this skill alone for full migrations — pair with **SKILL-002**. --- ## Repository Type Matrix Every repository in this organization is one of three types. The type governs which template variant to use and how to configure post-generation steps. | Type | Visibility | Primary Consumers | Schema Required | AI CODEOWNER | LFS Required | |---|---|---|---|---|---| | `public-standard` | Public | Humans + AI (read) | No | No | Optional | | `private-internal` | Private | Org members | No | Optional | Likely yes | | `ai-exclusive` | Private (default) | AI agents | Yes | **Yes** | Context-dependent | > **Inclusive design note:** Even `public-standard` repos should include machine-readable > frontmatter in their README. Humans ignore it. AIs depend on it. Cost: 8 lines of YAML. --- ## Template Repository — Directory Structure ``` {{ TEMPLATE_REPO }}/ │ ├── .github/ │ ├── CODEOWNERS ← Required. Controls required reviewers. │ ├── FUNDING.yml ← Optional. For open-source repos. │ ├── repo-config.yml ← CUSTOMIZE THIS per generated repo. │ │ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ ├── feature_request.yml │ │ └── migration_task.yml ← City/project migration tracking. │ │ │ ├── PULL_REQUEST_TEMPLATE.md │ │ │ └── workflows/ │ ├── ci.yml ← Base CI: lint, test, build. │ ├── labels-sync.yml ← Syncs labels from .github/labels.yml │ ├── migration-validate.yml ← Validates migration readiness. │ └── ai-schema-validate.yml ← For ai-exclusive repos only. │ ├── docs/ │ ├── README.md ← Documentation root. │ ├── ARCHITECTURE.md ← System/design decisions. │ ├── MIGRATION.md ← Migration readiness checklist. │ └── CHANGELOG.md ← Keep a changelog format. │ ├── schema/ ← AI-EXCLUSIVE REPOS ONLY. │ ├── manifest.json ← Machine-readable repo metadata. │ ├── schema.json ← Data schema for this repo's domain. │ └── openapi.yml ← API spec if applicable. │ ├── src/ ← Project source (rename as needed). ├── tests/ │ ├── .gitattributes ← LFS config (see below). ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ← Required for all public repos. ├── README.md ← See frontmatter spec below. └── SECURITY.md ``` --- ## File Content Specifications ### README.md — Machine-Readable Frontmatter (All Repo Types) All READMEs should begin with YAML frontmatter. Humans skip it; AI reads it first. This is the minimal investment for maximal AI-inclusivity. ```yaml --- repo-type: "public-standard" # public-standard | private-internal | ai-exclusive project-id: "{{ CITY_PROJECT_ID }}" org: "{{ ORG_NAME }}" domain: "" # infrastructure|energy|housing|governance|transport|data version: "0.1.0" migration-status: "fresh" # fresh | in-progress | migrated | archived migration-origin: "{{ MIGRATION_ORIGIN }}" ai-readable: true ai-consumers: - name: "{{ AI_BOT_ACCOUNT }}" access: "read" # read | read-write | none inclusive-design: true language: "en" # primary language; i18n-ready last-validated: "{{ DATE }}" maintainer: "{{ PRIMARY_CONTACT }}" --- ``` For **ai-exclusive** repos, extend with: ```yaml --- # ... base fields above ... repo-type: "ai-exclusive" ai-consumers: - name: "{{ AI_BOT_ACCOUNT }}" access: "read-write" auth-type: "{{ AI_AUTH_TYPE }}" schema-ref: "./schema/schema.json" manifest-ref: "./schema/manifest.json" human-readable: false # Signals to human contributors: AI-first content write-format: "json" # json | yaml | markdown | mixed structured-output: true --- ``` --- ### .github/repo-config.yml — Per-Repo Configuration This file is what makes the template *scalable*. After generating from template, a contributor (human or AI) edits only this file to configure repo-specific behavior. Everything else adapts via Actions workflows that read this config. ```yaml # .github/repo-config.yml # Edit this file after generating from template. # See SKILL-001 for full documentation. # # NOTE: This file is read by CI workflows. Breaking the YAML syntax will fail all checks. repo: name: "{{ REPO_NAME }}" # Set to actual repo name on generation type: "public-standard" # public-standard | private-internal | ai-exclusive domain: "" # Required: infrastructure|energy|housing|governance|transport|data|other language: "en" # Primary language (ISO 639-1) description: "" # One-sentence description migration: origin: "{{ MIGRATION_ORIGIN }}" # fresh | github.com | gitlab | ado | bitbucket | svn | mercurial | other fidelity: "source-history" # source-snapshot | source-history | full-metadata dry-run-completed: false # Set true after dry-run validation production-migration-date: "" # YYYY-MM-DD when production migration occurred ai_access: enabled: false # Set true for ai-exclusive repos agents: - name: "{{ AI_BOT_ACCOUNT }}" role: "reader" # reader | contributor | admin auth_type: "fine-grained-pat" # Resolved: fine-grained-pat packages_access: false # Fine-grained PATs cannot access GitHub Packages (AB-010) # Set a separate classic PAT secret if packages are needed schema_required: false # Set true for ai-exclusive human_contributors_allowed: true # Set false for strictly AI-exclusive branches: default: "{{ DEFAULT_BRANCH }}" protected: - "{{ DEFAULT_BRANCH }}" require_reviews: 1 # Number of required approvals require_signed_commits: false # Set true for AI repos (audit trail) dismiss_stale_reviews: true labels: use_org_defaults: true # Inherits org label set from labels-sync workflow custom: [] # Add repo-specific labels here ci: run_on_pr: true run_migration_validate: false # Set true when migrating content into this repo run_ai_schema_validate: false # Set true for ai-exclusive repos ``` --- ### .github/CODEOWNERS ``` # CODEOWNERS # See: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/ # customizing-your-repository/about-code-owners # # Pattern: [ ...] # Last matching rule wins. # Default: all files require primary contact review * @{{ PRIMARY_CONTACT }} # .github/ directory requires org admin .github/ @{{ PRIMARY_CONTACT }} # Schema files (AI-exclusive repos) require AI agent sign-off # Uncomment for ai-exclusive repos: # schema/ @{{ AI_BOT_ACCOUNT }} # Docs require primary contact docs/ @{{ PRIMARY_CONTACT }} # Migration checklist requires primary contact docs/MIGRATION.md @{{ PRIMARY_CONTACT }} ``` --- ### .gitattributes — LFS and Line Endings This configuration handles large files common in infrastructure/city planning projects. Geo data files are flagged for LFS to avoid repo size failures during migration. ```gitattributes # .gitattributes # Git LFS and line-ending normalization for city infrastructure repos # Normalize line endings * text=auto # LFS: Binary files *.bin filter=lfs diff=lfs merge=lfs -text *.exe filter=lfs diff=lfs merge=lfs -text # LFS: Archives *.zip filter=lfs diff=lfs merge=lfs -text *.tar filter=lfs diff=lfs merge=lfs -text *.tar.gz filter=lfs diff=lfs merge=lfs -text *.7z filter=lfs diff=lfs merge=lfs -text # LFS: Documents (city planning reports, specs) *.pdf filter=lfs diff=lfs merge=lfs -text *.docx filter=lfs diff=lfs merge=lfs -text *.pptx filter=lfs diff=lfs merge=lfs -text # LFS: GIS / Geospatial data (CRITICAL for city relocation context) *.geojson filter=lfs diff=lfs merge=lfs -text *.shp filter=lfs diff=lfs merge=lfs -text *.kml filter=lfs diff=lfs merge=lfs -text *.kmz filter=lfs diff=lfs merge=lfs -text *.gpkg filter=lfs diff=lfs merge=lfs -text *.tiff filter=lfs diff=lfs merge=lfs -text *.tif filter=lfs diff=lfs merge=lfs -text # LFS: Large data files *.csv filter=lfs diff=lfs merge=lfs -text *.parquet filter=lfs diff=lfs merge=lfs -text # LFS: Media *.mp4 filter=lfs diff=lfs merge=lfs -text *.mov filter=lfs diff=lfs merge=lfs -text *.png filter=lfs diff=lfs merge=lfs -text *.jpg filter=lfs diff=lfs merge=lfs -text # Enforce Unix line endings for scripts *.sh text eol=lf *.bash text eol=lf # Enforce Windows line endings for Windows batch files *.bat text eol=crlf *.cmd text eol=crlf ``` --- ### .github/ISSUE_TEMPLATE/migration_task.yml City-scale migration task tracker. Used for tracking repository or data migrations within the project workflow. ```yaml name: Migration Task description: Track a migration of data, repositories, or infrastructure. title: "[MIGRATION] " labels: ["migration", "needs-triage"] assignees: - {{ PRIMARY_CONTACT }} body: - type: dropdown id: migration-type attributes: label: Migration Type options: - Repository migration (code/history) - Data migration (city records, GIS, documents) - Infrastructure migration (systems, services) - Organization migration validations: required: true - type: dropdown id: origin attributes: label: Migration Origin options: - GitHub.com (another org or repo) - GitLab - Azure DevOps - Bitbucket - SVN / Subversion - Local filesystem - Other validations: required: true - type: input id: source-url attributes: label: Source URL or Path placeholder: "https://..." - type: dropdown id: fidelity attributes: label: Required Fidelity description: How much history and metadata do you need? options: - Source snapshot (code only, no history) - Source + history (code and git log) - Full fidelity (code, history, issues, PRs, metadata) validations: required: true - type: textarea id: repo-size attributes: label: Repository Size (if known) description: Include largest file size and total size. Flag if >1GB. - type: checkboxes id: checklist attributes: label: Pre-Migration Checklist options: - label: Dry-run migration completed - label: Users notified - label: Large files (>100MB) identified and handled - label: LFS configured - label: Branch protection rules documented for post-migration restore - label: CI/CD integrations noted for post-migration reconnection - type: textarea id: notes attributes: label: Notes ``` --- ### schema/manifest.json — AI-Exclusive Repos ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "manifestVersion": "1.0.0", "repoType": "ai-exclusive", "projectId": "{{ CITY_PROJECT_ID }}", "org": "{{ ORG_NAME }}", "domain": "", "description": "", "schemaRef": "./schema.json", "openApiRef": "./openapi.yml", "aiConsumers": [ { "name": "{{ AI_BOT_ACCOUNT }}", "access": "read-write", "authType": "{{ AI_AUTH_TYPE }}" } ], "dataFormats": ["json", "yaml"], "updateFrequency": "on-commit", "semanticVersioning": true, "lastValidated": null, "humanReadable": false, "inclusiveDesign": true } ``` --- ## Step-by-Step: Creating the Template Repository ### Prerequisites - GitHub CLI installed: `gh --version` - Authenticated: `gh auth status` - Admin access to `{{ ORG_NAME }}` - Git LFS installed (for geo/large file support): `git lfs version` ### Step 1 — Create the base repository ```bash gh repo create {{ ORG_NAME }}/{{ TEMPLATE_REPO }} \ --public \ --description "Org-standard repository template for {{ ORG_NAME }}" \ --clone cd {{ TEMPLATE_REPO }} ``` ### Step 2 — Initialize the directory structure ```bash # Create all required directories mkdir -p .github/ISSUE_TEMPLATE mkdir -p .github/workflows mkdir -p docs mkdir -p schema mkdir -p src mkdir -p tests # Create placeholder files so directories commit touch .github/ISSUE_TEMPLATE/.gitkeep touch schema/.gitkeep touch src/.gitkeep touch tests/.gitkeep ``` ### Step 3 — Populate with template files Copy the file contents from this skill's specifications above into each file. Substitute all `{{ }}` variables before committing. ```bash # Quick variable substitution example (Linux/macOS) ORG="{{ ORG_NAME }}" CONTACT="{{ PRIMARY_CONTACT }}" AI_BOT="{{ AI_BOT_ACCOUNT }}" find . -type f \( -name "*.md" -o -name "*.yml" -o -name "*.json" \) \ -exec sed -i \ -e "s/{{ ORG_NAME }}/$ORG/g" \ -e "s/{{ PRIMARY_CONTACT }}/$CONTACT/g" \ -e "s/{{ AI_BOT_ACCOUNT }}/$AI_BOT/g" \ {} + ``` ### Step 4 — Initialize Git LFS ```bash git lfs install # Add LFS tracking for all patterns in .gitattributes git lfs track "*.geojson" "*.shp" "*.pdf" "*.tiff" git add .gitattributes ``` ### Step 5 — Commit and push ```bash git add . git commit -m "chore: initialize organization repository template - Adds standard directory structure - Configures Git LFS for large/geo files - Adds CODEOWNERS, issue templates, PR template - Adds CI workflow stubs - Adds repo-config.yml for per-repo customization - Configures migration task issue template - Adds AI-exclusive repo schema structure Part of: {{ CITY_PROJECT_ID }} Org: {{ ORG_NAME }}" git push origin {{ DEFAULT_BRANCH }} ``` ### Step 6 — Enable template flag ⚠️ This CANNOT be done via `gh repo create`. Must use the API after creation. ```bash gh api repos/{{ ORG_NAME }}/{{ TEMPLATE_REPO }} \ -X PATCH \ -f is_template=true ``` Verify: ```bash gh api repos/{{ ORG_NAME }}/{{ TEMPLATE_REPO }} \ --jq '.is_template' # Expected: true ``` ### Step 7 — Set branch protection rules on the template Branch protection is NOT copied to generated repos (see Known Gaps below and AB-004). Set it on the template as a reference model, then reapply via post-generation script. ```bash # Requires: {{ ORG_TIER }} must be Team or Enterprise Cloud for full protection options. # Free/Pro: limited branch protection features available. gh api repos/{{ ORG_NAME }}/{{ TEMPLATE_REPO }}/branches/{{ DEFAULT_BRANCH }}/protection \ -X PUT \ --input - <<'EOF' { "required_status_checks": { "strict": true, "contexts": ["ci"] }, "enforce_admins": false, "required_pull_request_reviews": { "required_approving_review_count": 1, "dismiss_stale_reviews": true, "require_code_owner_reviews": true }, "restrictions": null, "allow_force_pushes": false, "allow_deletions": false } EOF ``` --- ## Step-by-Step: Generating a New Repository from Template ### Via GitHub CLI (Recommended) ```bash gh repo create {{ ORG_NAME }}/NEW-REPO-NAME \ --template {{ ORG_NAME }}/{{ TEMPLATE_REPO }} \ --public \ --description "Description of what this repo is for" \ --clone ``` For private repos: ```bash gh repo create {{ ORG_NAME }}/NEW-REPO-NAME \ --template {{ ORG_NAME }}/{{ TEMPLATE_REPO }} \ --private \ --clone ``` ### Via REST API (For Automation / AI Agents) ```bash curl -L -X POST \ -H "Authorization: Bearer $GITHUB_TOKEN" \ -H "Accept: application/vnd.github+json" \ https://api.github.com/repos/{{ ORG_NAME }}/{{ TEMPLATE_REPO }}/generate \ -d '{ "owner": "{{ ORG_NAME }}", "name": "new-repo-name", "description": "Repository description", "private": false, "include_all_branches": false }' ``` `include_all_branches: false` — only copies the default branch. Set `true` to copy all branches (useful when template has `staging`, `development` branches pre-configured). --- ## Post-Generation Configuration Checklist ⚠️ These items are NOT automatically copied from the template. They must be applied to every generated repo. Automate this with the `post-generate.sh` script below, or use the post-generation GitHub Actions workflow. ``` REQUIRED (all repo types): [ ] Update /.github/repo-config.yml with repo-specific settings [ ] Update README.md frontmatter (repo-type, domain, description) [ ] Set branch protection rules (see Step 7 above, run against new repo) [ ] Add repo to relevant org teams: gh api orgs/{{ ORG_NAME }}/teams/{team_slug}/repos/{{ ORG_NAME }}/{repo} -X PUT \ -f permission=push [ ] Set repository topics: gh repo edit {{ ORG_NAME }}/new-repo --add-topic "{{ CITY_PROJECT_ID }}" \ --add-topic "{domain}" [ ] Sync labels (trigger labels-sync workflow manually): gh workflow run labels-sync.yml --repo {{ ORG_NAME }}/new-repo [ ] Verify CODEOWNERS is correct for this repo REQUIRED (private-internal repos): [ ] Set visibility to private (if not done at generation) [ ] Add relevant teams with appropriate permissions REQUIRED (ai-exclusive repos): [ ] Set ai_access.enabled = true in repo-config.yml [ ] Update schema/manifest.json with repo-specific data [ ] Configure CODEOWNERS to include {{ AI_BOT_ACCOUNT }} [ ] Enable "Require signed commits" in branch protection [ ] Grant {{ AI_BOT_ACCOUNT }} collaborator access: gh api repos/{{ ORG_NAME }}/new-repo/collaborators/{{ AI_BOT_ACCOUNT }} \ -X PUT -f permission=push [ ] Run ai-schema-validate workflow to confirm schema integrity [ ] Set has_wiki = false, has_issues per project needs ``` ### Post-Generation Automation Script Save as `scripts/post-generate.sh` in the template repo and run after creating new repos: ```bash #!/usr/bin/env bash # post-generate.sh # Run after creating a new repo from {{ TEMPLATE_REPO }} # Usage: ./post-generate.sh REPO_NAME REPO_TYPE [TEAM_SLUG] # # REPO_TYPE: public-standard | private-internal | ai-exclusive # TEAM_SLUG: optional — GitHub team to grant push access set -euo pipefail REPO_NAME="${1:?Error: REPO_NAME required}" REPO_TYPE="${2:?Error: REPO_TYPE required (public-standard|private-internal|ai-exclusive)}" TEAM_SLUG="${3:-}" ORG="{{ ORG_NAME }}" DEFAULT_BRANCH="{{ DEFAULT_BRANCH }}" AI_BOT="{{ AI_BOT_ACCOUNT }}" echo "==> Configuring $ORG/$REPO_NAME (type: $REPO_TYPE)" # 1. Set branch protection echo "--> Setting branch protection on $DEFAULT_BRANCH" gh api "repos/$ORG/$REPO_NAME/branches/$DEFAULT_BRANCH/protection" \ -X PUT \ --input - < Setting repository topics" gh repo edit "$ORG/$REPO_NAME" \ --add-topic "{{ CITY_PROJECT_ID }}" \ --add-topic "$REPO_TYPE" # 3. Add to team if specified if [[ -n "$TEAM_SLUG" ]]; then echo "--> Adding to team: $TEAM_SLUG" gh api "orgs/$ORG/teams/$TEAM_SLUG/repos/$ORG/$REPO_NAME" \ -X PUT -f permission=push fi # 4. AI-exclusive specific config if [[ "$REPO_TYPE" == "ai-exclusive" ]]; then echo "--> Configuring AI-exclusive settings" # Grant AI bot access gh api "repos/$ORG/$REPO_NAME/collaborators/$AI_BOT" \ -X PUT -f permission=push # Disable wiki (reduce noise for AI consumers) gh api "repos/$ORG/$REPO_NAME" \ -X PATCH -f has_wiki=false echo " --> Don't forget: update schema/manifest.json and README.md frontmatter" fi # 5. Private-internal: ensure visibility if [[ "$REPO_TYPE" == "private-internal" ]]; then echo "--> Verifying private visibility" VISIBILITY=$(gh api "repos/$ORG/$REPO_NAME" --jq '.visibility') if [[ "$VISIBILITY" != "private" ]]; then echo " WARNING: Repo is $VISIBILITY — expected private. Set manually." fi fi echo "==> Done. Post-generation checklist:" echo " [ ] Update /.github/repo-config.yml" echo " [ ] Update README.md frontmatter" echo " [ ] Sync labels: gh workflow run labels-sync.yml --repo $ORG/$REPO_NAME" if [[ "$REPO_TYPE" == "ai-exclusive" ]]; then echo " [ ] Update schema/manifest.json" echo " [ ] Run: gh workflow run ai-schema-validate.yml --repo $ORG/$REPO_NAME" fi ``` --- ## Scaling This Template to Other Organizations This template is designed to be forked. Organizations adopting it need to: 1. **Fork the template repo** into their own org: ```bash gh repo fork {{ ORG_NAME }}/{{ TEMPLATE_REPO }} --org TARGET_ORG --clone ``` 2. **Replace all `{{ }}` variables** with target org values: ```bash find . -type f \( -name "*.md" -o -name "*.yml" -o -name "*.json" \) \ -exec sed -i 's/{{ ORG_NAME }}/TARGET_ORG/g' {} + # ... repeat for each variable ``` 3. **Re-enable template flag**: ```bash gh api repos/TARGET_ORG/{{ TEMPLATE_REPO }} -X PATCH -f is_template=true ``` 4. **Customize** `repo-config.yml` defaults, CODEOWNERS, and CI workflows for the new org's standards. 5. **Document** any divergence from this base template in the fork's README — this creates a traceable lineage of template adaptations. --- ## Migration-Ready Configuration Summary **Confirmed:** Migration origin is mixed — some repos fresh, some migrated from existing sources. Set `migration.origin` per repo in `repo-config.yml`. Default in the template is `fresh`; override when bringing in external repos. For repositories that contain or will receive migrated data, set in `repo-config.yml`: ```yaml migration: origin: "fresh" # Override per repo: github.com | gitlab | ado | bitbucket | svn | other fidelity: "source-history" dry-run-completed: false ``` For **fresh repos** (no migration): leave defaults, set `dry-run-completed: true` immediately. For **migrating repos**: follow SKILL-002 decision tree for the specific origin. Common paths for a mixed-origin org: - GitHub.com → GitHub.com: GHE Importer (source + history + metadata) - Local filesystem → GitHub: `git init` + push (Section 5.10 in SKILL-002) - GitLab/ADO → GitHub: Git CLI bare clone + mirror push (Section 5.3/5.5 in SKILL-002) And verify for all migrating repos: - `.gitattributes` includes LFS patterns for all file types in source repo - Source repo size measured (`git-sizer`) before migration - Files >100MB identified and LFS-tracked or removed from history - CI includes `migration-validate.yml` workflow For repos receiving migrations >1GB total or files >100MB individual: - See **SKILL-002**, Tool Selection section — large files affect available tools - See **SKILL-002**, AB-008 — no documented self-serve path exists for repos >40GB --- ## Known Gaps and Cross-References These are documented absences in GitHub's own documentation that affect this template. See **SKILL-003** for the methodology. See **SKILL-002** for full migration absence registry. | Absence ID | Issue | Impact on This Template | |---|---|---| | AB-004 | Template generation does NOT copy branch protection, secrets, environments, labels, or team permissions | Must use post-generation script above | | AB-007 | GitHub migration docs contain zero information about AI bot / GitHub App behavior during migration | `ai-exclusive` repo migration behavior is undocumented — validate manually | | AB-001 | Template repos and migration tooling are never documented together | This skill bridges that gap; no official documentation parallel | | AB-010 | Fine-grained PATs cannot authenticate to GitHub Packages | AI agents using fine-grained PATs need a **separate classic PAT** for any container image or npm package access — store as `PACKAGES_READ_PAT` org secret | | SAS-001 | Security configurations have no API management path | Org-level security config (Team plan: Dependabot, branch protection) must be applied via UI after bulk repo creation | | PKG-001 | Fine-grained PATs not supported by GitHub Packages (documented GitHub limitation) | Classic PAT required for `ghcr.io` and `npm.pkg.github.com` auth outside of Actions | ### AB-010 — Fine-Grained PAT Cannot Authenticate to GitHub Packages (New, This Session) **Type:** Version Discrepancy (feature not yet supported — cross-references PKG-001 in SKILL-010) **Severity:** High **Discovery date:** 2026-05-29 **Triggered by:** Q3 resolution — fine-grained PAT selected as AI auth type **Problem:** Fine-grained PATs are the correct AI agent auth choice for repo access, but they cannot authenticate to GitHub Packages (`ghcr.io`, `npm.pkg.github.com`). If any AI agent workflow needs to pull a container image or install an org-scoped npm package, it will fail silently or with a 401 that doesn't explain the PAT type mismatch. **Workaround:** 1. Store a classic PAT with only `read:packages` scope as `PACKAGES_READ_PAT` in org secrets 2. AI agent workflows use the fine-grained PAT for all repo operations 3. AI agent workflows use `PACKAGES_READ_PAT` only for Packages pull operations 4. Document this split in each AI-exclusive repo's `schema/manifest.json`: ```json "aiConsumers": [{ "name": "{{ AI_BOT_ACCOUNT }}", "authType": "fine-grained-pat", "packagesAuthType": "classic-pat", "packagesAuthNote": "Separate secret: PACKAGES_READ_PAT — read:packages scope only" }] ``` **Watch for updates at:** https://docs.github.com/en/packages/learn-github-packages/introduction-to-github-packages --- ## Further Reading - [GitHub REST API: Create a repository using a template](https://docs.github.com/en/rest/repos/repos#create-a-repository-using-a-template) - [About CODEOWNERS](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners) - [Creating a template repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository) - [Managing large files](https://docs.github.com/en/repositories/working-with-files/managing-large-files) - SKILL-002: GitHub Repository Migration Docs - SKILL-003: Albert's Tooling (Finding the Absence)