Skip to main content

Runbook: Migration to upsquad-ai Enterprise Org

Tracker: #604 Target duration: 2–4 hours focused Owner: Founder (enterprise admin actions) + devops-engineer (scripted automation) Prereq: All gate conditions in #604 met

Summary

Three repos move from personal orgs (ashik-upsqd-x, upsqdvb) to enterprise org upsquad-ai. Issues, PRs, git history, webhooks, secrets, CI workflows all preserved via GitHub's native repo transfer. Go module path changes (github.com/upsquad-ai/upsquad-coregithub.com/upsquad-ai/upsquad-core) — mechanical rename across 381 Go files + 21 proto files, automated by scripts/migration/rename-go-module.sh.

Execution order

Phase 0 — Founder prep (before Day M)

Human-only actions in the GitHub enterprise admin panel:

  1. Create 7 Enterprise-owned GitHub Apps under Enterprise → Settings → GitHub Apps. Set visibility: Internal. Permissions mirror current bots:

    • Issues + Pull requests: Read & Write
    • Contents: Read & Write (for write agents), Read (for read-only)
    • Metadata: Read
    • Members: Read

    Apps to create: upsquad-product-manager, upsquad-project-manager, upsquad-principal-architect, upsquad-backend-sme, upsquad-frontend-sme, upsquad-qa-engineer, upsquad-devops-engineer.

  2. Install each app on upsquad-ai org. Record the installation ID for each.

  3. Set up the shared key directory on the dev machine (one-time, requires sudo):

    # Create shared group both users belong to
    sudo groupadd -f upsquad-devs
    sudo usermod -a -G upsquad-devs vb
    sudo usermod -a -G upsquad-devs ashik

    # Create shared directory, group-readable, not world-readable
    sudo mkdir -p /opt/upsquad-keys
    sudo chown root:upsquad-devs /opt/upsquad-keys
    sudo chmod 2750 /opt/upsquad-keys # setgid so new files inherit group

    # Verify: both users should appear in the group
    getent group upsquad-devs

    Both users need to log out + back in (or run newgrp upsquad-devs) for group membership to take effect.

  4. Download each app's private key (.pem file) from GitHub and place them in the shared directory:

    /opt/upsquad-keys/upsquad-product-manager.private-key.pem
    /opt/upsquad-keys/upsquad-project-manager.private-key.pem
    /opt/upsquad-keys/upsquad-principal-architect.private-key.pem
    /opt/upsquad-keys/upsquad-backend-sme.private-key.pem
    /opt/upsquad-keys/upsquad-frontend-sme.private-key.pem
    /opt/upsquad-keys/upsquad-qa-engineer.private-key.pem
    /opt/upsquad-keys/upsquad-devops-engineer.private-key.pem

    Set permissions so only the upsquad-devs group can read:

    sudo chown root:upsquad-devs /opt/upsquad-keys/*.pem
    sudo chmod 0640 /opt/upsquad-keys/*.pem
  5. Record app IDs and installation IDs in /opt/upsquad-keys/config.yaml:

    apps:
    product-manager:
    app_id: 1234567
    installation_id: 9876543
    project-manager:
    app_id: ...
    installation_id: ...
    # ... 5 more
    sudo chown root:upsquad-devs /opt/upsquad-keys/config.yaml
    sudo chmod 0640 /opt/upsquad-keys/config.yaml
  6. Create GitHub Project v2 named "UpsQuad Delivery Board" under upsquad-ai org:

    • Fields: Wave (single-select A–L), Track (backend/frontend/devops/qa/docs), PRD (text), Status (status), Sprint (iteration)
    • Views: "Active work", "By wave", "By track"
    • Automation rules: issue opened → Todo; PR linked → Review; issue closed → Done
  7. Confirm enterprise policy: 2FA enforcement enabled; audit log export configured (the security-posture decisions from #604).

Phase 1 — This PR lands (before migration day)

Prep scripts + runbook committed to main:

  • scripts/migration/rename-go-module.sh
  • scripts/migration/rename-client-refs.sh
  • scripts/migration/smoke-test.sh
  • docs/runbooks/migration-to-upsquad-ai.md (this file)

Phase 2 — Migration day (founder + orchestrator)

Communicate: post "repos moving to upsquad-ai — expect 2-4 hours — all existing clones + URLs will redirect" message to team.

Transfer repos in increasing risk order, verifying after each:

2.1 Transfer upsqdvb/upsquad-adminupsquad-ai/upsquad-admin

# Run with founder's PAT that has admin on both orgs
curl -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${FOUNDER_PAT}" \
https://api.github.com/repos/upsqdvb/upsquad-admin/transfer \
-d '{"new_owner":"upsquad-ai"}'

# Wait ~30s for GitHub to complete the transfer

# Verify
gh api repos/upsquad-ai/upsquad-admin --jq '.full_name' # should return upsquad-ai/upsquad-admin
git -C /opt/upsquad/upsquad-admin remote set-url origin git@github.com:upsquad-ai/upsquad-admin.git

# Install the 7 GitHub Apps on this repo via the upsquad-ai org settings
# (they're already installed on the org per Phase 0; verify repo-level permission grant)

# Run smoke test
bash scripts/migration/smoke-test.sh upsquad-admin

2.2 Transfer upsqdvb/upsquad-clientupsquad-ai/upsquad-client

Same pattern. Smoke-test includes npx tsc --noEmit + npx vitest run.

2.3 Transfer ashik-upsqd-x/upsquad-coreupsquad-ai/upsquad-core

Same pattern. After transfer but BEFORE merging any new code:

# Update git remote locally
git -C /opt/upsquad/upsquad-core remote set-url origin git@github.com:upsquad-ai/upsquad-core.git
git fetch origin

# Create rename branch
git checkout -b chore/rename-go-module-to-upsquad-ai origin/main

# Run the automated rename
bash scripts/migration/rename-go-module.sh

# Verify
go build ./...
go vet ./...
go test ./... -race -count=1
bash hack/rls-check.sh

# Commit + push + open PR via REST API (use new bot token path)
git add -A
git commit -m "chore: rename Go module to github.com/upsquad-ai/upsquad-core"
GH_TOKEN=$(python3 /opt/upsquad/upsquad-core/scripts/gh-token.py backend-sme) \
git push "https://x-access-token:${GH_TOKEN}@github.com/upsquad-ai/upsquad-core.git" HEAD

# Open PR via REST API and merge

Phase 3 — Post-migration cleanup

  1. Update scripts/gh-token.py in all 3 repos to point at new central key store (/opt/upsquad-keys/). Commit + PR in each.

  2. Re-declare any org-scoped Actions secrets at upsquad-ai org level. Audit Secrets inherited from the old orgs.

  3. Update memory files (list below). These live outside the repo in /home/vb/.claude/projects/-opt-upsquad-upsquad-core/memory/:

    • reference_github_access.md — new org, new path pattern
    • reference_client_repo_keys.md — bot keys now central, no per-repo
    • reference_admin_portal_setup.md — same
    • feedback_bot_identity.mdgh-token.py signature changed
    • feedback_issues_live_with_code.md — now enforceable in one org, rule still correct
    • project_multi_repo.md — update org name
    • MEMORY.md — sanity check
  4. Update CLAUDE.md in each of the 3 repos — replace org references.

  5. Close migration tracker #604 with a final summary comment.

Phase 4 — Enterprise security hardening

(Already locked per #604 decisions.)

  1. Enforce 2FA on all enterprise members via Enterprise → Policies → Required 2FA.
  2. Enable audit log export via Enterprise → Settings → Audit log → Streaming to external destination (can be stored locally as JSON for now).
  3. Deferred: SAML SSO + IP allowlist (separate initiative).

Verification per repo (the smoke-test script checks all of these)

  • gh api repos/upsquad-ai/<repo> returns valid metadata
  • Old URL redirects for git clone
  • python3 scripts/gh-token.py <agent-slug> returns a working token
  • Test issue creation under each of the 7 bot identities
  • CI runs green on a trivial PR (uses the registry-pull workflow)
  • Issues + PRs auto-appear in the upsquad-ai Project board
  • Full test suite green (go test -race for core, npx vitest run for client)
  • Branch protection rules still enforced

Rollback

Each phase has a rollback:

  • Transfer rollback: reverse transfer via same REST endpoint — repo goes back to original owner. All URL redirects updated automatically. If done within 1 hour, zero user-visible impact.
  • Go module rename rollback: git revert the rename commit; imports revert to old module path. Works via GitHub's repo-redirect even if still on new org.
  • Bot token rollback: keep old per-repo scripts/gh-token.py functional during transition by not deleting old apps until Phase 4 is stable for 1 week.

Known non-transferred items

Per GitHub documentation (verified 2026-04-17):

  • GitHub App installations — must be re-installed on the new org. Covered by Phase 0.
  • GitHub Pages — not used in these repos; no impact.
  • Org-level Actions secrets — must be re-declared at upsquad-ai org level (enterprise-level secrets not yet used). Covered by Phase 3.2.

All other items (issues, PRs, git history, branches, tags, webhooks, repo secrets, branch protection, CI workflows, stars, watchers, fork relationships, CI check history) transfer automatically.

Time budget

PhaseTimeWho
0 (founder prep)1–2hFounder, done before Day M
1 (merge this PR)15minOrchestrator
2.1 admin transfer + smoke30minFounder + orchestrator
2.2 client transfer + smoke30minFounder + orchestrator
2.3 core transfer + Go rename + smoke60–90minFounder + orchestrator
3 post-cleanup30minOrchestrator
4 security15minFounder
Total Day M~3h

Contingencies

  • Go rename PR fails build — most likely cause is a symlinked or vendor path missed by sed. Manually inspect with grep -rn "ashik-upsqd-x/upsquad-core" and patch those files.
  • Bot token fails auth post-transfer — GitHub App may need explicit install on new repo even after org-level install. Revisit Phase 0 step 2.
  • CI fails on first PR post-transfer — usually transient (Actions runner needs to re-cache). Retry the workflow.
  • Issue references from old org don't render — GitHub redirects work but for cleanliness, run scripts/migration/rename-client-refs.sh in any remaining repo to update #Nupsquad-ai/repo#N style refs.

After declaring migration complete

Follow-up work unblocks:

  • Wave I #569 (Admin UI) — dispatch directly in new org
  • PRDs #558, #573, #615, #623 — approve + HLD work starts in new org
  • Wave J #570, Wave K #571, Wave L #572 — migration prep (Phase 2) of PRD #549 (cutover + drop-legacy)