diff --git a/.github/README.md b/.github/README.md
new file mode 100644
index 0000000..77583e4
--- /dev/null
+++ b/.github/README.md
@@ -0,0 +1,65 @@
+# CI/CD と開発者向けドキュメント
+
+この `.github/` ディレクトリには、チーム情報とプロフィール表示を自動で同期するためのワークフローが置かれています。リポジトリ全体の概要は [リポジトリ root の README](../README.md) を参照してください。
+
+## Workflow 一覧
+
+| Workflow | Trigger | 役割 |
+| --- | --- | --- |
+| `.github/workflows/tf-plan.yaml` | `terraform/**` を含む PR | `terraform plan` を実行し差分を PR コメントに投稿 |
+| `.github/workflows/tf-apply.yaml` | main への push(`terraform/**`) / 手動 | `terraform apply` → 続けて `sync-core-members` を起動 |
+| `.github/workflows/sync-core-members.yml` | `tf-apply` からの起動 / 6時間ごとの cron / 手動 / `repository_dispatch` | 最新年度の `core-members-YYYY` team を取得し `data/core_members.yaml` と `profile/README.md` を再生成する PR を自動作成 |
+| `.github/workflows/validate-profile.yml` | `data/core_members.yaml` や `profile/README.md` を含む PR | `render_members.py --check` で README の再生成漏れを検出 |
+
+## 認証
+
+- **GitHub API (team / membership の書込)**: GitHub App (`Organization → Members: Read & Write`) の installation token を `actions/create-github-app-token@v2` で発行し Terraform provider に渡します。tfcmt の PR コメント投稿や `sync-core-members` の起動 (`gh workflow run`) には App token ではなく Actions 標準の `GITHUB_TOKEN` を使います(App には repo 権限がないため)。
+- **自動生成 PR (`sync-core-members`)**: 別の GitHub App から発行した token で署名付き commit を作成し PR を出します。`peter-evans/create-pull-request` の `sign-commits: true` を利用するため、App installation token 経由の GraphQL 署名になり、GitHub 上で "Verified" バッジが付きます。App 側の必要権限:
+ - Organization → Members: Read
+ - Repository → Contents: Read & Write
+ - Repository → Pull requests: Read & Write
+- **Terraform state**: Google Cloud Storage bucket `ynufes-tech-gh-tf-state` に保存します。GitHub Actions から Workload Identity Federation で SA `gh-actions@ynufes-tech-gh.iam.gserviceaccount.com` に impersonate してアクセスします。
+
+### 必要なリポジトリ secrets
+
+| 名前 | 用途 |
+| --- | --- |
+| `TF_GH_APP_ID`, `TF_GH_APP_PRIVATE_KEY` | `tf-plan` / `tf-apply` |
+| `SYNC_GH_APP_ID`, `SYNC_GH_APP_PRIVATE_KEY` | `sync-core-members`(署名付き PR 作成) |
+
+## ローカル開発
+
+ツールは [aqua](https://aquaproj.github.io/) で管理しています。
+
+```bash
+aqua i -l
+```
+
+Python の依存は [uv](https://docs.astral.sh/uv/) で管理しています。
+
+```bash
+uv sync
+```
+
+### プロフィール README の再生成チェック
+
+```bash
+uv run scripts/render_members.py --check
+```
+
+### 現在の Core Members を取得して YAML を更新 (要 `gh` ログイン)
+
+```bash
+uv run scripts/fetch_core_members.py --org ynufes-tech --out data/core_members.yaml
+uv run scripts/render_members.py
+```
+
+### Terraform
+
+```bash
+cd terraform
+terraform init
+terraform plan
+```
+
+state backend は GCS です。ローカルから叩く場合は `gcloud auth application-default login` の後、SA への impersonate を許可するか、同 SA の鍵で認証してください。
diff --git a/.github/workflows/sync-core-members.yml b/.github/workflows/sync-core-members.yml
new file mode 100644
index 0000000..301eb53
--- /dev/null
+++ b/.github/workflows/sync-core-members.yml
@@ -0,0 +1,112 @@
+name: Sync Core Members
+
+on:
+ schedule:
+ - cron: "17 */6 * * *"
+ workflow_dispatch:
+ repository_dispatch:
+ types:
+ - core-members-changed
+
+permissions:
+ contents: write
+ pull-requests: write
+
+concurrency:
+ group: sync-core-members
+ cancel-in-progress: false
+
+jobs:
+ sync:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Generate GitHub App token
+ id: app_token
+ uses: actions/create-github-app-token@v2
+ with:
+ app-id: ${{ secrets.SYNC_GH_APP_ID }}
+ private-key: ${{ secrets.SYNC_GH_APP_PRIVATE_KEY }}
+ owner: ynufes-tech
+
+ - name: Setup uv
+ uses: astral-sh/setup-uv@v5
+
+ - name: Snapshot previous members
+ run: cp data/core_members.yaml /tmp/core_members_prev.yaml
+
+ - name: Fetch current Core Members
+ env:
+ GH_TOKEN: ${{ steps.app_token.outputs.token }}
+ run: |
+ uv run scripts/fetch_core_members.py \
+ --org ynufes-tech \
+ --out data/core_members.yaml
+
+ - name: Render profile README
+ run: uv run scripts/render_members.py
+
+ - name: Build PR body
+ id: diff
+ run: |
+ uv run python - <<'PY' > /tmp/pr_body.md
+ import pathlib
+ import yaml
+
+ prev = yaml.safe_load(pathlib.Path("/tmp/core_members_prev.yaml").read_text()) or {}
+ curr = yaml.safe_load(pathlib.Path("data/core_members.yaml").read_text()) or {}
+
+ def names(section):
+ return set(section.get("members", []) or [])
+
+ def diff_section(label, prev_section, curr_section):
+ prev_names = names(prev_section or {})
+ curr_names = names(curr_section or {})
+ added = sorted(curr_names - prev_names, key=str.lower)
+ removed = sorted(prev_names - curr_names, key=str.lower)
+ slug = (curr_section or {}).get("team_slug", "-")
+ out = [
+ f"### {label} (team: `{slug}`)",
+ f"- 現在のメンバー数: {len(curr_names)}",
+ ]
+ if added:
+ out += ["", "**追加**", *[f"- @{n}" for n in added]]
+ if removed:
+ out += ["", "**削除**", *[f"- @{n}" for n in removed]]
+ if not added and not removed:
+ out += ["", "差分なし"]
+ return out
+
+ lines = ["## Core Members / Members 同期", ""]
+ lines += diff_section(
+ "Core Members", prev.get("core_members"), curr.get("core_members")
+ )
+ lines += ["", ""]
+ lines += diff_section(
+ "Members", prev.get("all_members"), curr.get("all_members")
+ )
+ lines += [
+ "",
+ "このPRは GitHub Actions が自動生成しています。",
+ "メンバー構成そのものの編集は `terraform/team_memberships.tf` で行ってください。",
+ ]
+ print("\n".join(lines))
+ PY
+
+ - name: Create pull request
+ uses: peter-evans/create-pull-request@v7
+ with:
+ token: ${{ steps.app_token.outputs.token }}
+ branch: automation/core-members-sync
+ commit-message: "chore: sync Core Members membership"
+ title: "chore: Core Members のメンバー一覧を同期"
+ body-path: /tmp/pr_body.md
+ delete-branch: true
+ sign-commits: true
+ committer: "${{ steps.app_token.outputs.app-slug }}[bot] <${{ steps.app_token.outputs.app-slug }}[bot]@users.noreply.github.com>"
+ author: "${{ steps.app_token.outputs.app-slug }}[bot] <${{ steps.app_token.outputs.app-slug }}[bot]@users.noreply.github.com>"
+ labels: |
+ members
+ automation
diff --git a/.github/workflows/tf-apply.yaml b/.github/workflows/tf-apply.yaml
new file mode 100644
index 0000000..72e6305
--- /dev/null
+++ b/.github/workflows/tf-apply.yaml
@@ -0,0 +1,67 @@
+name: Terraform Apply
+
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - terraform/**
+ - .github/workflows/tf-apply.yaml
+ workflow_dispatch:
+
+permissions:
+ id-token: write
+ contents: read
+ actions: write
+ pull-requests: write
+
+concurrency:
+ group: terraform-apply
+ cancel-in-progress: false
+
+jobs:
+ apply:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: terraform
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Generate GitHub App token (org admin)
+ id: app_token
+ uses: actions/create-github-app-token@v2
+ with:
+ app-id: ${{ secrets.TF_GH_APP_ID }}
+ private-key: ${{ secrets.TF_GH_APP_PRIVATE_KEY }}
+ owner: ynufes-tech
+
+ - name: Authenticate to Google Cloud
+ uses: google-github-actions/auth@v2
+ with:
+ workload_identity_provider: projects/516174501149/locations/global/workloadIdentityPools/default/providers/github
+ service_account: gh-actions@ynufes-tech-gh.iam.gserviceaccount.com
+
+ - name: Setup aqua
+ uses: aquaproj/aqua-installer@v3.1.0
+ with:
+ aqua_version: v2.36.1
+
+ - name: Terraform init
+ run: terraform init -input=false
+
+ - name: Terraform apply (tfcmt)
+ env:
+ TF_VAR_github_token: ${{ steps.app_token.outputs.token }}
+ # tfcmt のコメント投稿は repo 権限を持つ Actions 標準トークンで行う
+ # (App token は org Members 権限のみで PR コメントを投稿できない)
+ GITHUB_TOKEN: ${{ github.token }}
+ run: tfcmt apply -- terraform apply -input=false -auto-approve
+
+ - name: Trigger profile sync
+ env:
+ # workflow_dispatch は GITHUB_TOKEN 起動でも新しい run が作られる
+ # (App token には Actions: write がないため使えない)
+ GH_TOKEN: ${{ github.token }}
+ run: gh workflow run sync-core-members.yml -R ${{ github.repository }}
diff --git a/.github/workflows/tf-plan.yaml b/.github/workflows/tf-plan.yaml
new file mode 100644
index 0000000..65528ec
--- /dev/null
+++ b/.github/workflows/tf-plan.yaml
@@ -0,0 +1,58 @@
+name: Terraform Plan
+
+on:
+ pull_request:
+ paths:
+ - terraform/**
+ - .github/workflows/tf-plan.yaml
+
+permissions:
+ id-token: write
+ contents: read
+ pull-requests: write
+
+jobs:
+ plan:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: terraform
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Generate GitHub App token (org admin)
+ id: app_token
+ uses: actions/create-github-app-token@v2
+ with:
+ app-id: ${{ secrets.TF_GH_APP_ID }}
+ private-key: ${{ secrets.TF_GH_APP_PRIVATE_KEY }}
+ owner: ynufes-tech
+
+ - name: Authenticate to Google Cloud
+ uses: google-github-actions/auth@v2
+ with:
+ workload_identity_provider: projects/516174501149/locations/global/workloadIdentityPools/default/providers/github
+ service_account: gh-actions@ynufes-tech-gh.iam.gserviceaccount.com
+
+ - name: Setup aqua
+ uses: aquaproj/aqua-installer@v3.1.0
+ with:
+ aqua_version: v2.36.1
+
+ - name: Terraform fmt
+ run: terraform fmt -check -recursive
+
+ - name: Terraform init
+ run: terraform init -input=false
+
+ - name: Terraform validate
+ run: terraform validate -no-color
+
+ - name: Terraform plan (tfcmt)
+ env:
+ TF_VAR_github_token: ${{ steps.app_token.outputs.token }}
+ # tfcmt の PR コメント投稿は repo 権限を持つ Actions 標準トークンで行う
+ # (App token は org Members 権限のみで PR コメントを投稿できない)
+ GITHUB_TOKEN: ${{ github.token }}
+ run: tfcmt plan -patch -- terraform plan -input=false -no-color -out=tfplan
diff --git a/.github/workflows/validate-profile.yml b/.github/workflows/validate-profile.yml
new file mode 100644
index 0000000..32fc651
--- /dev/null
+++ b/.github/workflows/validate-profile.yml
@@ -0,0 +1,23 @@
+name: Validate Profile Render
+
+on:
+ pull_request:
+ paths:
+ - data/core_members.yaml
+ - scripts/render_members.py
+ - profile/README.md
+ - .github/workflows/validate-profile.yml
+ workflow_dispatch:
+
+jobs:
+ validate-render:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup uv
+ uses: astral-sh/setup-uv@v5
+
+ - name: Verify README is rendered
+ run: uv run scripts/render_members.py --check
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..00da56f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+.venv/
+__pycache__/
+*.pyc
+
+# Terraform
+terraform/.terraform/
+terraform/tfplan
+terraform/*.tfplan
+terraform/*.tfstate
+terraform/*.tfstate.*
diff --git a/.tfcmt.yaml b/.tfcmt.yaml
new file mode 100644
index 0000000..ddb788e
--- /dev/null
+++ b/.tfcmt.yaml
@@ -0,0 +1,2 @@
+---
+ci: github-actions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9325edf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,47 @@
+# ynufes-tech/.github
+
+`ynufes-tech` Org のチームの管理と、プロフィールページを管理するレポジトリです。
+
+- `profile/README.md`: Organization プロフィールとして表示される README
+- `terraform/`: Organization のチームを Terraform で管理
+- `scripts/` + `.github/workflows/`: team のメンバー情報を取得し、プロフィールのメンバー一覧を自動更新するスクリプト
+
+## 全体の流れ
+
+メンバーは Terraform コード(`terraform/team_memberships.tf`)で管理しています。メンバー情報を更新するにはこのファイルを編集しPRを作成してください。
+Mergeされるとチーム情報とプロフィール表示の両方が自動で更新されます。
+
+```mermaid
+flowchart TB
+ subgraph Phase1["1. GitHub チーム情報の更新"]
+ direction TB
+ PR1["① Terraform コードを編集
(team / メンバーの追加・削除)"]
+ Review1["② Review & Merge"]
+ Apply["③ GitHub Actions: Terraform apply
GitHub team / メンバーシップを更新"]
+ Teams[("GitHub Organization の
team / 所属")]
+ PR1 --> Review1 ==> Apply --> Teams
+ end
+
+ subgraph Phase2["2. Org README の更新"]
+ direction TB
+ Sync["④ GitHub Actions: team メンバーを取得して
Org README を再生成してPRを作成"]
+ Review2["⑤ 自動生成された
Org README 更新PRをMerge"]
+ OrgReadme[("Org README メンバー一覧")]
+ Sync ==> Review2 --> OrgReadme
+ end
+
+ Teams --> Sync
+```
+
+## チームについて
+
+| team | 用途 |
+| --- | --- |
+| `core-members-YYYY` | 年度ごとの現役メンバー。Organization README のメンバー一覧表示は最新年度が対象 |
+| `all-members` | 技術部局に所属したことのあるメンバー |
+
+チーム情報の変更は必ず `terraform/team_memberships.tf` を編集する PR で行ってください。
+
+## CI/CD とローカル開発
+
+ワークフローの詳細・必要な secrets・ローカル開発手順は [.github/README.md](.github/README.md) を参照してください。
diff --git a/aqua.yaml b/aqua.yaml
new file mode 100644
index 0000000..6576bb8
--- /dev/null
+++ b/aqua.yaml
@@ -0,0 +1,7 @@
+---
+registries:
+ - type: standard
+ ref: v4.360.0
+packages:
+ - name: hashicorp/terraform@v1.9.5
+ - name: suzuki-shunsuke/tfcmt@v4.14.0
diff --git a/data/core_members.yaml b/data/core_members.yaml
new file mode 100644
index 0000000..9af07fc
--- /dev/null
+++ b/data/core_members.yaml
@@ -0,0 +1,31 @@
+# このファイルは GitHub Actions (`sync-core-members.yml`) が自動生成しています。
+# 手動で編集しないでください。
+# メンバーの追加・削除は `terraform/team_memberships.tf` を編集する PR で行ってください。
+core_members:
+ team_slug: core-members-2026
+ year: 2026
+ members:
+ - Hasegawa18
+ - huugayamashita
+ - Issy0507
+ - MTowa
+ - somanosuke
+all_members:
+ team_slug: all-members
+ members:
+ - aguri1102
+ - akari4455
+ - fujisawakanon
+ - Hasegawa18
+ - HashikawaNana
+ - hayato19
+ - hinata0629
+ - huugayamashita
+ - Issy0507
+ - ma2192006
+ - MTowa
+ - Sakiho-Ishii
+ - Shion1305
+ - shuma7
+ - somanosuke
+ - tomoyahiroe
diff --git a/profile/README.md b/profile/README.md
index 034c5a6..c619799 100644
--- a/profile/README.md
+++ b/profile/README.md
@@ -11,8 +11,19 @@
# Members
-[
](https://github.com/hayato19) [
](https://github.com/hinata0629) [
](https://github.com/shuma7) [
](https://github.com/HashikawaNana) [
](https://github.com/shion1305) [
](https://github.com/tomoyahiroe)
+
+> [!IMPORTANT]
+> 以下のメンバーアイコン一覧は GitHub team から自動生成しています。手動で編集しないでください。
+> メンバーの追加・削除は Terraform (`terraform/team_memberships.tf`) で管理しています。
+### Core Members / 現役メンバー `core-members-2026`
+
+[
](https://github.com/Hasegawa18) [
](https://github.com/huugayamashita) [
](https://github.com/Issy0507) [
](https://github.com/MTowa) [
](https://github.com/somanosuke)
+
+### Members (OB/OG含む)
+
+[
](https://github.com/aguri1102) [
](https://github.com/akari4455) [
](https://github.com/fujisawakanon) [
](https://github.com/Hasegawa18) [
](https://github.com/HashikawaNana) [
](https://github.com/hayato19) [
](https://github.com/hinata0629) [
](https://github.com/huugayamashita) [
](https://github.com/Issy0507) [
](https://github.com/ma2192006) [
](https://github.com/MTowa) [
](https://github.com/Sakiho-Ishii) [
](https://github.com/Shion1305) [
](https://github.com/shuma7) [
](https://github.com/somanosuke) [
](https://github.com/tomoyahiroe)
+
# Our Tech Stack
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..055a275
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,11 @@
+[project]
+name = "ynufes-github-profile-automation"
+version = "0.1.0"
+description = "Automation scripts for ynufes-tech .github profile members"
+requires-python = ">=3.12"
+dependencies = [
+ "pyyaml>=6.0.3",
+]
+
+[tool.uv]
+package = false
diff --git a/scripts/fetch_core_members.py b/scripts/fetch_core_members.py
new file mode 100644
index 0000000..7c4c577
--- /dev/null
+++ b/scripts/fetch_core_members.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+
+import argparse
+import re
+import subprocess
+from dataclasses import dataclass
+from pathlib import Path
+
+import yaml
+
+HEADER_COMMENT = (
+ "# このファイルは GitHub Actions (`sync-core-members.yml`) が自動生成しています。\n"
+ "# 手動で編集しないでください。\n"
+ "# メンバーの追加・削除は `terraform/team_memberships.tf` を編集する PR で行ってください。\n"
+)
+
+
+TEAM_SLUG_PATTERN = re.compile(r"^core-members-(\d{4})$")
+ALL_MEMBERS_SLUG = "all-members"
+
+
+@dataclass
+class Args:
+ org: str
+ out: Path
+
+
+def parse_args() -> Args:
+ parser = argparse.ArgumentParser(
+ description=(
+ "ynufes-tech org の `core-members-YYYY`(最新年度)と `all-members` の "
+ "メンバー一覧を取得し YAML に書き出します"
+ )
+ )
+ parser.add_argument("--org", default="ynufes-tech")
+ parser.add_argument("--out", default="data/core_members.yaml")
+ ns = parser.parse_args()
+ return Args(org=ns.org, out=Path(ns.out))
+
+
+def gh_api_paginate(path: str, jq: str | None = None) -> str:
+ cmd = ["gh", "api", "--paginate", path]
+ if jq is not None:
+ cmd += ["--jq", jq]
+ # stderr は capture せず CI ログにそのまま流す(gh のエラー内容を隠さない)
+ result = subprocess.run(cmd, check=True, text=True, stdout=subprocess.PIPE)
+ return result.stdout
+
+
+def list_team_slugs(org: str) -> list[str]:
+ raw = gh_api_paginate(f"/orgs/{org}/teams", jq=".[].slug")
+ return [line.strip() for line in raw.splitlines() if line.strip()]
+
+
+def core_member_years(slugs: list[str]) -> list[int]:
+ years = {
+ int(m.group(1)) for slug in slugs if (m := TEAM_SLUG_PATTERN.match(slug))
+ }
+ return sorted(years, reverse=True)
+
+
+def fetch_team_members(org: str, slug: str) -> list[str]:
+ raw = gh_api_paginate(
+ f"/orgs/{org}/teams/{slug}/members",
+ jq=".[].login",
+ )
+ logins = [line.strip() for line in raw.splitlines() if line.strip()]
+ logins.sort(key=str.lower)
+ return logins
+
+
+def pick_core_members(org: str, years: list[int]) -> dict:
+ # 次年度 team がメンバー未定のまま先行作成されても sync が止まらないよう、
+ # メンバーが 1 人以上いる最新年度を採用する
+ for year in years:
+ slug = f"core-members-{year}"
+ logins = fetch_team_members(org, slug)
+ if logins:
+ return {
+ "team_slug": slug,
+ "year": year,
+ "members": logins,
+ }
+ raise SystemExit(
+ "すべての `core-members-YYYY` team のメンバーが 0 件でした。 "
+ "README 誤空化を防ぐため処理を中止します。"
+ )
+
+
+def main() -> None:
+ args = parse_args()
+
+ slugs = list_team_slugs(args.org)
+
+ years = core_member_years(slugs)
+ if not years:
+ raise SystemExit(
+ f"`core-members-YYYY` 形式の team が org `{args.org}` に見つかりません。 "
+ "Terraform apply 後に再実行してください。"
+ )
+
+ if ALL_MEMBERS_SLUG not in slugs:
+ raise SystemExit(
+ f"team `{ALL_MEMBERS_SLUG}` が org `{args.org}` に見つかりません。"
+ )
+
+ core = pick_core_members(args.org, years)
+
+ all_logins = fetch_team_members(args.org, ALL_MEMBERS_SLUG)
+ if not all_logins:
+ raise SystemExit(
+ f"team `{ALL_MEMBERS_SLUG}` のメンバーが 0 件でした。 "
+ "README 誤空化を防ぐため処理を中止します。"
+ )
+
+ payload = {
+ "core_members": core,
+ "all_members": {
+ "team_slug": ALL_MEMBERS_SLUG,
+ "members": all_logins,
+ },
+ }
+
+ args.out.parent.mkdir(parents=True, exist_ok=True)
+ body = yaml.safe_dump(
+ payload,
+ allow_unicode=True,
+ sort_keys=False,
+ default_flow_style=False,
+ )
+ args.out.write_text(HEADER_COMMENT + body, encoding="utf-8")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/render_members.py b/scripts/render_members.py
new file mode 100755
index 0000000..c524c39
--- /dev/null
+++ b/scripts/render_members.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+
+import argparse
+import re
+from pathlib import Path
+from typing import Any
+
+import yaml
+
+START_MARKER = ""
+END_MARKER = ""
+
+
+def parse_args() -> argparse.Namespace:
+ parser = argparse.ArgumentParser(
+ description=(
+ "data/core_members.yaml から profile/README.md のメンバーアイコンを再生成します"
+ )
+ )
+ parser.add_argument("--members-file", default="data/core_members.yaml")
+ parser.add_argument("--readme-file", default="profile/README.md")
+ parser.add_argument("--check", action="store_true")
+ return parser.parse_args()
+
+
+def load_payload(path: Path) -> dict[str, Any]:
+ raw = yaml.safe_load(path.read_text(encoding="utf-8"))
+ if not isinstance(raw, dict):
+ raise SystemExit(f"{path} の形式が不正です (mapping ではありません)")
+ return raw
+
+
+def extract_usernames(entries: Any) -> list[str]:
+ if not isinstance(entries, list):
+ return []
+
+ usernames: list[str] = []
+ for entry in entries:
+ if not isinstance(entry, str):
+ continue
+ username = entry.strip()
+ if not username:
+ continue
+ usernames.append(username)
+
+ usernames.sort(key=str.lower)
+ return usernames
+
+
+def build_icons_line(usernames: list[str]) -> str:
+ if not usernames:
+ return "_メンバーはまだ登録されていません。_"
+
+ icons = [
+ f'[
](https://github.com/{username})'
+ for username in usernames
+ ]
+ return " ".join(icons)
+
+
+def build_generated_block(payload: dict[str, Any]) -> str:
+ core = payload.get("core_members", {}) or {}
+ all_members = payload.get("all_members", {}) or {}
+
+ core_slug = str(core.get("team_slug") or "core-members-YYYY")
+ all_slug = str(all_members.get("team_slug") or "all-members")
+
+ core_rows = extract_usernames(core.get("members"))
+ all_rows = extract_usernames(all_members.get("members"))
+
+ return "\n".join(
+ [
+ "> [!IMPORTANT]",
+ "> 以下のメンバーアイコン一覧は GitHub team から自動生成しています。手動で編集しないでください。",
+ "> メンバーの追加・削除は Terraform (`terraform/team_memberships.tf`) で管理しています。",
+ "",
+ f"### Core Members / 現役メンバー `{core_slug}`",
+ "",
+ build_icons_line(core_rows),
+ "",
+ "### Members (OB/OG含む)",
+ "",
+ build_icons_line(all_rows),
+ ]
+ )
+
+
+def render(readme_text: str, generated_block: str) -> str:
+ pattern = re.compile(
+ rf"({re.escape(START_MARKER)}\n)(.*?)(\n{re.escape(END_MARKER)})",
+ re.DOTALL,
+ )
+ if not pattern.search(readme_text):
+ raise ValueError(
+ "README にメンバーブロックのマーカーがありません: "
+ f"{START_MARKER} ... {END_MARKER}"
+ )
+ return pattern.sub(
+ lambda m: m.group(1) + generated_block + m.group(3), readme_text
+ )
+
+
+def main() -> None:
+ args = parse_args()
+ payload = load_payload(Path(args.members_file))
+ generated_block = build_generated_block(payload)
+
+ readme_path = Path(args.readme_file)
+ before = readme_path.read_text(encoding="utf-8")
+ after = render(before, generated_block)
+
+ if args.check:
+ if before != after:
+ raise SystemExit(
+ "profile/README.md が最新ではありません。 "
+ "次を実行してください: uv run scripts/render_members.py"
+ )
+ return
+
+ if before != after:
+ readme_path.write_text(after, encoding="utf-8")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl
new file mode 100644
index 0000000..bc5d376
--- /dev/null
+++ b/terraform/.terraform.lock.hcl
@@ -0,0 +1,25 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/integrations/github" {
+ version = "6.13.0"
+ constraints = "~> 6.0"
+ hashes = [
+ "h1:2kD+4leuV8tBBXv+EPeehmfW6cDhIzVki61OXsGCtRI=",
+ "h1:y0Sujto8gttV86innNp/LTMzq7CqsFpBs7XKH8AlMl4=",
+ "zh:0ab29fc21699f34345cf0bbbe44745fd1b143b7c73b410c1dc4abe05ffad0a84",
+ "zh:1aed10d06755d420bb3a893bf548ab2932297a9d094c04c5a8501e949ca186ed",
+ "zh:2a6a11c21eae408055f45b9533c07afd2e845f6d496fd1b645aec2e873012103",
+ "zh:5dd05dee677f6ebdbed00cbb1b9be444ab2d1062d345cbc9ec50a47cb41b8622",
+ "zh:6b757d034831243d67ddda869eac4368cef539848bd97511f4d68f1aa38a9c88",
+ "zh:947c9b5b238f0364c57a705beabd24d3eea3159a6f3a24c07e3fbb13657ffae0",
+ "zh:a676549a98164b61630658cbeb6c17820331ca04a049dc9b5095996a0c31ffbe",
+ "zh:a8a81b7fe41dd61eb6a6fa5e08a4dd9ee070e862868252a7fd4cfce30364efee",
+ "zh:c26a9bca4865665084e7f59b1402d7aff34ee63a418d7401a0658fa280cad4d4",
+ "zh:c638d8d0762e62ea188f86302954ef4c92803f2160f0a45fca0cd13974bd3725",
+ "zh:e739a0b7e81ca816944a18a38e679f4015edf8be7ac319815cdea865ba7727d7",
+ "zh:ec099487ea3de8999c84b3b791e242d728461e51fe344832b37bd8d521201c77",
+ "zh:f016ff9e2daab5b88185cec0795213049d105439ffd585d3309a714514ccae13",
+ "zh:fbd1fee2c9df3aa19cf8851ce134dea6e45ea01cb85695c1726670c285797e25",
+ ]
+}
diff --git a/terraform/backend.tf b/terraform/backend.tf
new file mode 100644
index 0000000..3ef8e6f
--- /dev/null
+++ b/terraform/backend.tf
@@ -0,0 +1,6 @@
+terraform {
+ backend "gcs" {
+ bucket = "ynufes-tech-gh-tf-state"
+ prefix = "github-org"
+ }
+}
diff --git a/terraform/imports.tf b/terraform/imports.tf
new file mode 100644
index 0000000..2bd1ccb
--- /dev/null
+++ b/terraform/imports.tf
@@ -0,0 +1,59 @@
+import {
+ id = "9608186"
+ to = github_team.core_members_2024
+}
+
+import {
+ id = "12233900"
+ to = github_team.core_members_2025
+}
+
+import {
+ id = "15547740"
+ to = github_team.core_members_2026
+}
+
+import {
+ id = "16613363"
+ to = github_team.all_members
+}
+
+import {
+ id = "6360571"
+ to = github_team.core_members_2022
+}
+
+import {
+ id = "7550421"
+ to = github_team.core_members_2023
+}
+
+import {
+ id = "9608186"
+ to = github_team_members.core_members_2024
+}
+
+import {
+ id = "12233900"
+ to = github_team_members.core_members_2025
+}
+
+import {
+ id = "15547740"
+ to = github_team_members.core_members_2026
+}
+
+import {
+ id = "16613363"
+ to = github_team_members.all_members
+}
+
+import {
+ id = "6360571"
+ to = github_team_members.core_members_2022
+}
+
+import {
+ id = "7550421"
+ to = github_team_members.core_members_2023
+}
diff --git a/terraform/locals.tf b/terraform/locals.tf
new file mode 100644
index 0000000..9dd5e5d
--- /dev/null
+++ b/terraform/locals.tf
@@ -0,0 +1,61 @@
+locals {
+ core_members_2022 = [
+ "Shion1305",
+ ]
+
+ core_members_2023 = [
+ "HashikawaNana",
+ "Shion1305",
+ "hayato19",
+ "hinata0629",
+ "shuma7",
+ "tomoyahiroe",
+ ]
+
+ core_members_2024 = [
+ "aguri1102",
+ "akari4455",
+ "fujisawakanon",
+ "hayato19",
+ "hinata0629",
+ "ma2192006",
+ "shuma7",
+ ]
+
+ core_members_2025 = [
+ "aguri1102",
+ "akari4455",
+ "fujisawakanon",
+ "Hasegawa18",
+ "huugayamashita",
+ "Issy0507",
+ "ma2192006",
+ "Sakiho-Ishii",
+ "somanosuke",
+ ]
+
+ core_members_2026 = [
+ "Hasegawa18",
+ "huugayamashita",
+ "Issy0507",
+ "MTowa",
+ "somanosuke",
+ ]
+
+ all_members_maintainers = [
+ "Shion1305",
+ ]
+
+ all_members_union = toset(concat(
+ local.core_members_2022,
+ local.core_members_2023,
+ local.core_members_2024,
+ local.core_members_2025,
+ local.core_members_2026,
+ ))
+
+ all_members = {
+ for username in local.all_members_union :
+ username => contains(local.all_members_maintainers, username) ? "maintainer" : "member"
+ }
+}
diff --git a/terraform/provider.tf b/terraform/provider.tf
new file mode 100644
index 0000000..e5d99ac
--- /dev/null
+++ b/terraform/provider.tf
@@ -0,0 +1,9 @@
+variable "github_token" {
+ type = string
+ sensitive = true
+}
+
+provider "github" {
+ owner = "ynufes-tech"
+ token = var.github_token
+}
diff --git a/terraform/team_memberships.tf b/terraform/team_memberships.tf
new file mode 100644
index 0000000..5b1c414
--- /dev/null
+++ b/terraform/team_memberships.tf
@@ -0,0 +1,71 @@
+resource "github_team_members" "core_members_2022" {
+ team_id = github_team.core_members_2022.id
+
+ dynamic "members" {
+ for_each = toset(local.core_members_2022)
+ content {
+ username = members.value
+ role = "member"
+ }
+ }
+}
+
+resource "github_team_members" "core_members_2023" {
+ team_id = github_team.core_members_2023.id
+
+ dynamic "members" {
+ for_each = toset(local.core_members_2023)
+ content {
+ username = members.value
+ role = "member"
+ }
+ }
+}
+
+resource "github_team_members" "core_members_2024" {
+ team_id = github_team.core_members_2024.id
+
+ dynamic "members" {
+ for_each = toset(local.core_members_2024)
+ content {
+ username = members.value
+ role = "member"
+ }
+ }
+}
+
+resource "github_team_members" "core_members_2025" {
+ team_id = github_team.core_members_2025.id
+
+ dynamic "members" {
+ for_each = toset(local.core_members_2025)
+ content {
+ username = members.value
+ role = "member"
+ }
+ }
+}
+
+resource "github_team_members" "core_members_2026" {
+ team_id = github_team.core_members_2026.id
+
+ dynamic "members" {
+ for_each = toset(local.core_members_2026)
+ content {
+ username = members.value
+ role = "member"
+ }
+ }
+}
+
+resource "github_team_members" "all_members" {
+ team_id = github_team.all_members.id
+
+ dynamic "members" {
+ for_each = local.all_members
+ content {
+ username = members.key
+ role = members.value
+ }
+ }
+}
diff --git a/terraform/teams.tf b/terraform/teams.tf
new file mode 100644
index 0000000..6e37c3c
--- /dev/null
+++ b/terraform/teams.tf
@@ -0,0 +1,35 @@
+resource "github_team" "core_members_2024" {
+ name = "Core Members 2024"
+ description = "2024年度現役"
+ privacy = "closed"
+}
+
+resource "github_team" "core_members_2025" {
+ name = "Core Members 2025"
+ description = "2025年度現役"
+ privacy = "closed"
+}
+
+resource "github_team" "core_members_2026" {
+ name = "Core Members 2026"
+ description = "2026年度現役"
+ privacy = "closed"
+}
+
+resource "github_team" "all_members" {
+ name = "All Members"
+ description = "技術部局 全メンバー"
+ privacy = "closed"
+}
+
+resource "github_team" "core_members_2022" {
+ name = "Core Members 2022"
+ description = "2022年度現役"
+ privacy = "closed"
+}
+
+resource "github_team" "core_members_2023" {
+ name = "Core Members 2023"
+ description = "2023年度現役"
+ privacy = "closed"
+}
diff --git a/terraform/versions.tf b/terraform/versions.tf
new file mode 100644
index 0000000..5d14d23
--- /dev/null
+++ b/terraform/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = ">= 1.6"
+
+ required_providers {
+ github = {
+ source = "integrations/github"
+ version = "~> 6.0"
+ }
+ }
+}
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 0000000..432f4e0
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,60 @@
+version = 1
+revision = 3
+requires-python = ">=3.12"
+
+[[package]]
+name = "pyyaml"
+version = "6.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
+ { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
+ { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
+ { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
+ { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
+ { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
+ { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
+ { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
+ { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
+ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
+ { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
+ { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
+ { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
+ { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
+ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
+]
+
+[[package]]
+name = "ynufes-github-profile-automation"
+version = "0.1.0"
+source = { virtual = "." }
+dependencies = [
+ { name = "pyyaml" },
+]
+
+[package.metadata]
+requires-dist = [{ name = "pyyaml", specifier = ">=6.0.3" }]