Playbook: Adding a New Repository to the Ecosystem

When to use

Use when creating any new GitHub repository under radieu/ that becomes part of the Ecotrans / p24-infra ecosystem — web apps, Android apps, CLI tools, automation scripts, libraries.


Pre-flight checklist

Before creating the repo, decide:

QuestionNotes
Repo namekebab-case, descriptive, no abbreviations
VisibilityPrivate (default for all internal tooling); public only for OSS
Primary languageKotlin, Python, TypeScript, etc. — drives .gitignore choice
Secrets needed?If yes → plan a new SOPS file in p24-infra/secrets/
Supabase migrations?If yes → include supabase/migrations/ folder
CI/CD?GitHub Actions → add standard error-notification secrets
Vercel deploy?If Next.js → add to Vercel project after repo creation
CLAUDE.md needed?Yes — always add one for Claude Code sessions in the new repo

Step 1 — Create the GitHub repo

# Adjust --description and --gitignore as needed
gh repo create radieu/<repo-name> `
  --private `
  --description "<one-line description>" `
  --gitignore <language>   # e.g. Node, Python, Kotlin, Swift

Verify:

gh repo view radieu/<repo-name> --json name,visibility,defaultBranch

Step 2 — Clone locally (if active development from workstation)

git clone git@github.com:radieu/<repo-name>.git C:\code_2026\<repo-name>
cd C:\code_2026\<repo-name>

For agent-only repos (all work done via worktrees on VPS): skip local clone.


Step 3 — Initialize branch structure

The repo starts with main. Create dev and set it as default for PRs.

# Create dev branch from main
git checkout -b dev
git push origin dev
 
# Set dev as default branch (PRs target dev, not main)
gh api repos/radieu/<repo-name> -X PATCH -f default_branch=dev

Verify:

gh repo view radieu/<repo-name> --json defaultBranch
# Expected: {"defaultBranch":"dev"}

Step 4 — Set up standard labels

$repo = "radieu/<repo-name>"
 
# Delete GitHub default labels (optional — keep if preferred)
@("bug","documentation","duplicate","good first issue","help wanted","invalid","question","wontfix") | ForEach-Object {
  gh label delete $_ --repo $repo --yes 2>$null
}
 
# Create p24-infra standard labels
gh label create "bug"           --repo $repo --color "d73a4a" --description "Something is broken"
gh label create "enhancement"   --repo $repo --color "a2eeef" --description "New feature or improvement"
gh label create "plan"          --repo $repo --color "5319E7" --description "Design/planning issue"
gh label create "human-action"  --repo $repo --color "fbca04" --description "Waiting for human decision or action"
gh label create "queued"        --repo $repo --color "0e8a16" --description "Queued for implementation"
gh label create "patch"              --repo $repo --color "e4e669" --description "Small fix or tweak"
gh label create "ai-review-queued"  --repo $repo --color "0075ca" --description "PR queued for AI auto-review"
gh label create "ai-review-rejected" --repo $repo --color "d93f0b" --description "PR rejected by AI review — issue re-queued"

Step 5 — Add CLAUDE.md

Create a minimal CLAUDE.md at the repo root. Minimum required sections:

# CLAUDE.md — <Repo Name>
 
## Project Overview
<One-paragraph description of what this repo does and why.>
 
**GitHub repo:** `radieu/<repo-name>`
**Primary language:** <Kotlin / Python / TypeScript / etc.>
 
## Role
 
<What role does Claude play here? e.g. "Android Developer — builds and maintains the Kotlin app.">
 
## Repo structure
 
<Key folders and what they contain.>
 
## Commands
 
<How to build, test, run.>
 
## Secrets
 
<If applicable: which SOPS file holds credentials for this repo.>
Credentials: `p24-infra/secrets/<name>.env.sops`
 
## Branching
 
Same as p24-infra:
- `main` — tagged releases, never commit directly
- `dev` — integration branch, all PRs target here
- `feat/{issue}-{slug}`, `fix/{issue}-{slug}` — feature/fix branches

Step 5b — Set up .claude/ infrastructure (Claude Code permissions + skills)

Without this step, VS Code Claude Code extension will prompt permission for every tool call and no project-specific slash commands (/sr, /commit, /create-pr) will be available.

.claude/settings.json

Copy the template below and adjust the allow list to match the repo’s stack (remove Docker/SSH entries for pure app repos; keep ./gradlew for Android, pytest for Python):

$settingsPath = "C:\code_2026\<repo-name>\.claude\settings.json"
New-Item -ItemType Directory -Force (Split-Path $settingsPath) | Out-Null
[System.IO.File]::WriteAllText($settingsPath, @'
{
    "permissions": {
        "allow": [
            "Bash(git status)",
            "Bash(git diff*)",
            "Bash(git log*)",
            "Bash(git add*)",
            "Bash(git commit*)",
            "Bash(git checkout*)",
            "Bash(git merge*)",
            "Bash(git branch*)",
            "Bash(git push origin*)",
            "Bash(git push -u origin*)",
            "Bash(git fetch origin*)",
            "Bash(git ls-remote*)",
            "Bash(git show*)",
            "Bash(git stash*)",
            "Bash(git rebase*)",
            "Bash(gh *)",
            "Bash(ls *)",
            "Bash(find *)",
            "Bash(cat *)",
            "Bash(grep *)",
            "Bash(tail *)",
            "Bash(head *)",
            "Bash(wc *)",
            "Bash(mkdir -p *)",
            "Bash(cp *)",
            "Bash(mv *)",
            "Bash(touch *)",
            "Bash(curl *)",
            "mcp__github__get_file_contents",
            "mcp__github__list_branches",
            "mcp__github__list_commits",
            "mcp__github__list_issues",
            "mcp__github__list_pull_requests",
            "mcp__github__get_commit",
            "mcp__github__issue_read",
            "mcp__github__pull_request_read",
            "mcp__github__search_code",
            "mcp__github__search_issues",
            "mcp__github__search_pull_requests",
            "mcp__github__get_me",
            "mcp__github__add_issue_comment",
            "mcp__github__issue_write",
            "mcp__github__pull_request_review_write",
            "mcp__github__create_branch",
            "mcp__github__push_files",
            "mcp__github__create_pull_request",
            "mcp__github__update_pull_request",
            "mcp__github__merge_pull_request",
            "PowerShell",
            "Edit",
            "Write",
            "Read",
            "Glob",
            "Grep"
        ]
    }
}
'@, [System.Text.UTF8Encoding]::new($false))

Stack-specific additions to the allow list:

StackAdd to allow
Android / Kotlin"Bash(./gradlew *)", "Bash(adb *)"
Python"Bash(python *)", "Bash(python3 *)", "Bash(pytest *)", "Bash(pip *)"
Node.js / Next.js"Bash(npm *)", "Bash(node *)", "Bash(npx *)"
Server ops (SSH)add full SSH/Docker block from p24-infra/.claude/settings.json

.claude/commands/ — standard skill set

Copy three commands from p24-infra (they are generic enough to work in any repo):

$cmds = "C:\code_2026\<repo-name>\.claude\commands"
New-Item -ItemType Directory -Force $cmds | Out-Null
 
# sr — session report
Copy-Item "C:\code_2026\p24-infra\.claude\commands\sr.md" "$cmds\sr.md"
 
# commit — auto-commit with conventional message
Copy-Item "C:\code_2026\p24-infra\.claude\commands\commit.md" "$cmds\commit.md"

For create-pr.md: copy from p24-infra/.claude/commands/create-pr.md — the pipeline is milestone-only (the GitHub Projects v2 board sync was removed 2026-07-08). Adjust the --base argument if the target repo uses dev instead of main as its PR base branch.

Verification

# Confirm files created
Get-ChildItem "C:\code_2026\<repo-name>\.claude" -Recurse | Select-Object FullName
# Expected: settings.json, commands/sr.md, commands/commit.md, commands/create-pr.md

Open the repo in VS Code → type / in Claude Code chat → confirm sr, commit, create-pr appear in the autocomplete list.


Step 6 — Add AI agent collaborators and accept invitations

Send invitations from your local workstation (as radieu):

$repo = "radieu/<repo-name>"
gh api repos/$repo/collaborators/AI-Dev-BMS4-1 -X PUT -f permission=write
gh api repos/$repo/collaborators/AI-Dev-BMS4-2 -X PUT -f permission=write

Accept from bms-4 — runners are authenticated as their AI-Dev accounts and can accept directly:

$acceptScript = @'
#!/bin/bash
sleep 5  # wait for GitHub to propagate invitation
for USER in claude-runner claude-runner-2; do
  su -s /bin/bash $USER -c '
    for id in $(gh api /user/repository_invitations --jq ".[].id" 2>/dev/null); do
      gh api /user/repository_invitations/$id --method PATCH
      echo "Accepted $id as $(gh api /user --jq .login)"
    done
  '
done
'@
[System.IO.File]::WriteAllText("$env:TEMP\accept-invites.sh", $acceptScript, [System.Text.UTF8Encoding]::new($false))
scp "$env:TEMP\accept-invites.sh" root@54.36.123.110:/tmp/accept-invites.sh
ssh root@54.36.123.110 "bash /tmp/accept-invites.sh"

Verify:

gh api repos/$repo/collaborators --jq ".[].login"
# Expected: radieu, AI-Dev-BMS4-1, ai-dev-bms4-2

If a runner’s OAuth token has expired, re-authenticate using the device flow: docs/playbooks/worker-github-invite-acceptance.md §One-time setup


Step 7 — Register in dev_r_services (Supabase)

Using the canonical insert pattern from docs/playbooks/dev-r-services-insert.md. Choose service_type and element_type from the table in that playbook:

Repo typeservice_typeelement_type
Android / mobile appworkflowscript
Python automationworkflowscript
Next.js web appworkflowworkflow
CLI tool / libraryworkflowscript
Monitoring componentmonitoringcontainer
Add-Type -AssemblyName System.Web.Extensions
$ser = New-Object System.Web.Script.Serialization.JavaScriptSerializer
 
$env:SOPS_AGE_KEY_FILE = "C:\Users\konar\.age\p24-infra-keys.txt"
$lines = sops --decrypt --input-type dotenv --output-type dotenv C:\code_2026\p24-infra\secrets\monitoring.env.sops 2>$null
$token = ($lines | Where-Object { $_ -match "^SUPABASE_ACCESS_TOKEN=" } | Select-Object -First 1) -replace "^SUPABASE_ACCESS_TOKEN=", ""
 
$ref = "mwkqmgadqnkkihjdeqsi"
$url = "https://api.supabase.com/v1/projects/$ref/database/query"
 
$sql = @"
DO `$`$
BEGIN
  IF NOT EXISTS (SELECT 1 FROM dev_r_services WHERE service_name = '<repo-name>') THEN
    INSERT INTO dev_r_services (
      service_name, project_id, project_name,
      office_id, ws_id, app_id,
      service_type, element_type, status, owner,
      compliance_workbook, workbook_url, compliance_notes
    ) VALUES (
      '<repo-name>', 'p24-infra', 'p24-infra',
      'p24-devops', '99', 'et-app',
      '<service_type>', '<element_type>', 'active', 'radieu',
      'yes', 'docs/<repo-name>-operations.md',
      '<one-line note>'
    );
  END IF;
END `$`$;
"@
 
$body   = $ser.Serialize(@{query = $sql})
$bytes  = [System.Text.Encoding]::UTF8.GetBytes($body)
$req    = [System.Net.WebRequest]::Create($url)
$req.Method = "POST"; $req.ContentType = "application/json"
$req.Headers.Add("Authorization", "Bearer $token")
$req.ContentLength = $bytes.Length
$s = $req.GetRequestStream(); $s.Write($bytes, 0, $bytes.Length); $s.Close()
try {
  $result = (New-Object System.IO.StreamReader(($req.GetResponse()).GetResponseStream())).ReadToEnd()
  "OK: $result"
} catch [System.Net.WebException] {
  $err = (New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())).ReadToEnd()
  "ERR: $err"
}

Verify insert:

# Run a SELECT query using same Invoke-SbQuery helper
# Expected: one row with service_name = '<repo-name>'

Step 8 — Update ecosystem docs

C:\code_2026\CLAUDE.md — Projects table

Add a row:

| `<repo-name>` | `radieu/<repo-name>` | <one-line role> | <Stack> |

C:\code_2026\p24-infra\docs\infrastructure-overview.md

Add a subsection under the relevant group (Apps / Tools / Scripts) describing the new repo.


Step 9 — Language-specific setup

Kotlin / Android

# The .gitignore is already created by gh repo create --gitignore Kotlin
# Add standard Android extras to .gitignore:
$extras = @"
 
# Android/Gradle
local.properties
*.iml
.idea/
.gradle/
build/
app/build/
captures/
.externalNativeBuild/
.cxx/
*.apk
*.aab
*.ap_
"@
# Append via [System.IO.File]::WriteAllText (avoids CRLF issues)

Initial Android project:

  • Create in Android Studio: File → New Project → Empty Views Activity (Kotlin)
  • Set minimum SDK to API 26 (Android 8.0) unless lower is needed
  • Push the generated project to dev branch

Python CLI / automation

# pyproject.toml with ruff config (line-length=100, target-version=py311)
# requirements.txt / requirements-dev.txt
# pytest.ini pointing to tests/

Next.js / TypeScript

npx create-next-app@latest . --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"

Step 10 — (Optional) SOPS secrets file

If the new repo needs credentials:

# Create a new SOPS file for this repo's secrets
# See: docs/secrets-management.md §"When you add a NEW secret"
# File: p24-infra/secrets/<repo-name>.env.sops
# Keys example:
#   <REPO>_SUPABASE_URL=...
#   <REPO>_SUPABASE_SERVICE_KEY=...
 
# After creating: update .sops.yaml path_regex to include the new file pattern
# Commit: only the encrypted .env.sops file, never plaintext

Step 11 — (Optional) Transfer existing issues

To move issues from another repo (e.g., p24-infra) to the new repo:

# Transfer preserves body, comments, and most labels (by name match)
gh issue transfer <issue-number> radieu/<repo-name> --repo radieu/<source-repo>

After transfer:

  • The original issue gets a “transferred to” comment and closes with a redirect
  • Labels that don’t exist in target repo are dropped — create matching labels first (Step 4)
  • Milestones are NOT transferred — set them manually in the target repo

Verification checklist

  • gh repo view radieu/<repo-name> shows correct visibility and description
  • dev branch exists and is the default
  • All 6 standard labels created
  • CLAUDE.md committed on dev
  • .claude/settings.json created with stack-appropriate permissions
  • .claude/commands/sr.md, commit.md, create-pr.md present — verified in VS Code / dropdown
  • AI agent collaborators added and invitations accepted (verify with gh api repos/$repo/collaborators --jq '.[].login')
  • dev_r_services row inserted (SELECT confirms 1 row)
  • Ecosystem CLAUDE.md updated
  • Infrastructure overview updated

Escalation

If gh repo create fails: check gh auth status — ensure you are authenticated as radieu. If dev_r_services insert fails: see docs/playbooks/dev-r-services-insert.md for trigger-enforced columns. If issue transfer fails with “not authorized”: confirm AI agent is a collaborator on both repos.