Verify and lock project identity before ANY git push, Cloudflare deploy, or Supabase operation. Essential when working with multiple GitHub accounts (personal + work), multiple Cloudflare accounts, or multiple Supabase/Neon projects. Prevents wrong-account deploys, cross-project secret leaks, and git history contamination.
From cmnpx claudepluginhub tody-agent/codymaster --plugin cmThis skill uses the workspace's default tool permissions.
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Implements distributed tracing with Jaeger/Tempo for microservices, including Kubernetes/Docker setup and OpenTelemetry instrumentation (Python/Flask). Use for debugging latency, dependencies, and request flows.
Working across multiple projects, clients, and platforms means one wrong git push or wrangler deploy can publish work to the wrong account. This skill establishes a mandatory identity check before any operation that touches external services.
[!CAUTION] Real incidents this skill prevents:
- Pushed client code to personal GitHub repo
- Deployed to wrong Cloudflare account (different org's Pages project, billing confusion)
- Used personal Supabase
ANON_KEYin a client project (wrong DB entirely)git config user.emailwas personal email → commits show wrong author in client repo
NEVER push, deploy, or use secrets WITHOUT verifying identity first.
ASK: Which account? Which project? Which database?
ONE command verifies all three. Run it. Always.
ALWAYS before:
git push or git commit in a project with multiple account contextswrangler pages deploy or any Cloudflare operationMaintain this table in your head (or in .project-identity.json):
| Account | Purpose | When to Use | |
|---|---|---|---|
my-personal | Personal projects, experiments | personal email | Personal repos, side projects |
my-work-org | Client work | dev@workdomain.com | All client projects |
| Account ID | Purpose | Projects |
|---|---|---|
abc123def456ghi789jkl012mno345pqr | Client A / Org | project-1, project-2, app |
| (personal) | Personal experiments | personal side projects |
| Service | Account | Purpose |
|---|---|---|
| Supabase (Org) | org account | All Client A apps |
| Supabase (personal) | personal account | Experiments |
| Neon | per project | If used |
Every project MUST have a .project-identity.json in the project root:
{
"name": "my-awesome-project",
"description": "An awesome internal tool",
"github": {
"account": "my-work-org",
"org": "my-work-org",
"repo": "my_project_repo",
"remoteUrl": "https://github.com/my-work-org/my_project_repo.git",
"userEmail": "dev@workdomain.com"
},
"cloudflare": {
"accountId": "abc123def456ghi789jkl012mno345pqr",
"projectName": "my-frontend-app",
"stagingUrl": "https://my-app-staging.pages.dev",
"productionUrl": "https://myapp.workdomain.com",
"productionBranch": "production"
},
"database": {
"provider": "supabase",
"projectName": "my-database-project",
"urlVar": "SUPABASE_URL",
"anonKeyVar": "SUPABASE_ANON_KEY",
"serviceKeyVar": "SUPABASE_SERVICE_KEY",
"secretsStore": "cloudflare-secrets"
},
"i18n": {
"primary": "vi",
"languages": ["vi", "en", "th", "ph"],
"dir": "public/static/i18n"
}
}
[!IMPORTANT] Add
.project-identity.jsonto git but NEVER put actual secrets in it — only variable NAMES and account IDs. Secrets live in.dev.vars(local) or Cloudflare Secrets (production).
Run this before any push or deploy:
# Full identity check — GitHub + Git user + CF account + DB config
echo "=== GitHub CLI ===" && gh auth status 2>&1 | grep -E "Logged in|github.com" && \
echo "=== Git Remote ===" && git remote get-url origin && \
echo "=== Git User ===" && git config user.name && git config user.email && \
echo "=== Cloudflare ===" && cat wrangler.jsonc | grep -E "account_id|project|name" | head -5 && \
echo "=== DB Config ===" && cat .dev.vars 2>/dev/null | grep -E "URL|SUPABASE" | sed 's/=.*/=***/' && \
echo "=== Expected ===" && cat .project-identity.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print('GitHub:', d['github']['account'], '| CF:', d['cloudflare']['accountId'][:8]+'...', '| DB:', d['database']['provider'])"
☐ GitHub CLI: logged in as <EXPECTED ACCOUNT>
☐ git remote origin: points to <EXPECTED REPO URL>
☐ git config user.email: matches <EXPECTED EMAIL>
☐ wrangler.jsonc: account_id matches <EXPECTED CF ACCOUNT ID>
☐ .dev.vars: SUPABASE_URL points to <EXPECTED SUPABASE PROJECT>
# Check current
gh auth status
# Switch to work account
gh auth logout
gh auth login
# → Login with web browser → select my-work-org
# Fix git user for THIS repo (not global)
git config user.name "my-work-org"
git config user.email "dev@workdomain.com"
# Fix remote URL
git remote set-url origin https://github.com/my-work-org/REPO_NAME.git
# Check current CF account
wrangler whoami
# Look for account_id in wrangler.jsonc
grep account_id wrangler.jsonc
# Expected for Your Project: abc123def456ghi789jkl012mno345pqr
# Fix: update account_id in wrangler.jsonc
# Check which Supabase URL is in .dev.vars
grep SUPABASE_URL .dev.vars
# The URL pattern reveals the project: https://<PROJECT_ID>.supabase.co
# Compare with the project in .project-identity.json
# Fix: update .dev.vars with correct values
# Then restart wrangler dev
# See who authored the last few commits
git log --format="%h %an <%ae>" -5
# If wrong — amend last commit's author (before push only!)
git commit --amend --author="my-work-org <dev@workdomain.com>" --no-edit
# For multiple commits: rebase and re-author
git rebase -i HEAD~N # Then for each commit: edit → amend author → continue
When starting a new project, answer these questions FIRST:
Before writing any code or creating any repo, I need to lock identity:
1. **GitHub account**: Personal (my-personal) or Work (my-work-org)?
2. **Cloudflare account**: Which account ID?
3. **Database**: Which Supabase org? New project or existing?
4. **Languages**: Single locale or multi-language from day 1?
→ If multi-language: list all target languages now
Then create .project-identity.json BEFORE the first commit:
# Lock git identity to this project immediately
git config user.name "my-work-org"
git config user.email "dev@workdomain.com"
git remote set-url origin https://github.com/my-work-org/NEW_REPO.git
# Verify before first push
git config user.email # Must match expected
git remote get-url origin # Must match expected
gh auth status # Must show correct account
# Generate separate keys for each account
ssh-keygen -t ed25519 -C "dev@workdomain.com" -f ~/.ssh/id_my_work_org
ssh-keygen -t ed25519 -C "personal@..." -f ~/.ssh/id_personal
# ~/.ssh/config — route by host alias
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_my_work_org
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_personal
# For work projects:
git remote set-url origin git@github-work:my-work-org/REPO.git
# For personal projects:
git remote set-url origin git@github-personal:my-personal/REPO.git
# Global: personal (default for new repos)
git config --global user.name "my-personal"
git config --global user.email "personal@email.com"
# Per-repo override for work projects (run inside each work repo):
git config user.name "my-work-org"
git config user.email "dev@workdomain.com"
[!TIP] Use
includeIfin~/.gitconfigto auto-apply work identity for repos in specific directories:[includeIf "gitdir:~/Builder/ClientA/"] path = ~/.gitconfig-work
~/.gitconfig-work:[user] name = my-work-org email = dev@workdomain.com
NEW — Secrets don't just need to be hidden. They need to be ROTATED. Full rotation playbooks in
cm-secret-shieldLayer 5.
| Platform | Token Type | Max Lifetime | Where to Rotate |
|---|---|---|---|
| Supabase | anon_key | 90 days | Dashboard → Settings → API |
| Supabase | service_role_key | 30 days | Dashboard → Settings → API |
| Cloudflare | API Token | 90 days | Dashboard → My Profile → API Tokens |
| GitHub | Personal Access Token | 90 days | Settings → Developer Settings → PAT |
| OpenAI/Gemini | API Key | 90 days | Platform dashboard |
# 1. Update Cloudflare Secrets with new values
wrangler secret put SUPABASE_ANON_KEY
wrangler secret put SUPABASE_SERVICE_KEY
# 2. Update local .dev.vars
# 3. Redeploy
npm run deploy:staging
# 4. Verify: test staging URL
For emergency rotation (leaked secret), see
cm-secret-shieldEmergency Rotation Playbook.
❌ git push and see "Repository not found" or "Permission denied"
→ Wrong account. Run identity check.
❌ wrangler deploy succeeded but can't find it in your CF dashboard
→ Deployed to wrong CF account. Check wrangler.jsonc account_id.
❌ Authentication fails with correct password
→ `gh auth status` shows wrong account. Logout and login to correct one.
❌ Production app shows the wrong data / can't connect to DB
→ Wrong SUPABASE_URL or key. Check Cloudflare Secrets for the project.
❌ git log shows wrong author email on commits
→ git config user.email is wrong. Fix and amend before pushing.
❌ New repo was created under wrong GitHub org
→ Delete and recreate under correct org, then update remote URL.
# 1. Delete the push (if repo is private, remove sensitive data)
git push origin --delete <branch> # Remove the branch
# 2. If sensitive data was exposed: contact GitHub support immediately
# Also rotate any secrets that appeared in the code
# 3. Push to the correct repo:
git remote set-url origin https://github.com/CORRECT_ORG/CORRECT_REPO.git
git push origin <branch>
# 1. Log into correct CF account
# 2. Deploy immediately to overwrite:
CLOUDFLARE_ACCOUNT_ID=<CORRECT_ID> wrangler pages deploy dist --project-name <CORRECT_PROJECT>
# 3. Go to WRONG account's CF dashboard and delete the project or rollback deployment
# 1. Update Cloudflare Secrets with correct values:
wrangler secret put SUPABASE_URL # Enter correct URL
wrangler secret put SUPABASE_SERVICE_KEY # Enter correct key
wrangler secret put SUPABASE_ANON_KEY # Enter correct key
# 2. Redeploy to pick up new secrets
npm run deploy
# 3. Rotate the accidentally exposed keys in Supabase dashboard
| Skill | When |
|---|---|
cm-project-bootstrap | Identity lock is Phase 0 of every new project |
cm-safe-deploy | Gate 0 secret hygiene checks wrangler.jsonc |
cm-test-gate | Phase 4 secret hygiene in test gate setup |
cm-secret-shield | Layer 5 token lifecycle extends identity management |
One .project-identity.json. One verification command. Every push, every deploy.
Wrong account = wasted time, broken deployments, exposed client code. The check takes 3 seconds.
This is non-negotiable.