You shipped client-portal-v2 for Acme on gautam-dev/acme-portal. Three months later Acme asks for a bug fix. You search GitHub, find acme-portal, acme-portal-old, acme-portal-final, and acme-portal-GST-fix. Which one is production? Which account owns it — yours or the client's? Where is the deploy key?
Freelancers don't have a GitHub problem. They have a context problem. By project 12, you own 35 repos across 4 GitHub accounts, half private, half public, tech stacks from Next.js 16 to legacy PHP, and zero link to which client paid for what.
Why Repo Sprawl Kills Momentum
No source of truth. repoName alone misses visibility public|private, githubAccount, techStack[] — you can't answer a client in 30s. Orphaned credentials. Deploy token acme vercel maybe in 1Password, url src/lib/db/schema.ts:179 in Slack, key in ~/.ssh — four-tool hunt on redeploy. Invisible portfolio. Show me Next.js work is 20min of GitHub profiles without visibility public + techStack filters. Offboarding miss. You export 2 repos, miss api-webhooks-private under personal githubAccount without clientId src/lib/db/schema.ts:182.
A spreadsheet called Repos 2025 doesn't fix this. It has Repo | Link | Notes — no clientId FK, no projectId FK, no visibility enum, no techStack array, and links that rot.
The Linked Repo Graph: How RunoSO Models GitHub
RunoSO treats GitHub not as a bookmark list, but as one of six linked asset tables under tenant_${id} src/lib/db/tenant.ts:67, queryable via one API GET /api/assets/[category] src/app/api/assets/[category]/route.ts:97 where ALLOWED_CATEGORIES = ["domains","cloudflare","github","hosting","social","subscriptions"] src/app/api/assets/[category]/route.ts:91.
assetsGithub {
repoName varchar(255) notNull src/lib/db/schema.ts:178
url text src/lib/db/schema.ts:179
visibility varchar(50) public|private src/lib/db/schema.ts:180 // enum validated
githubAccount varchar(255) notNull src/lib/db/schema.ts:181
clientId uuid fk → clients.id src/lib/db/schema.ts:182 // who owns it
projectId uuid fk → projects.id src/lib/db/schema.ts:183 // which project built it
techStack text[] array src/lib/db/schema.ts:184 // Next.js, Tailwind v4, Drizzle
notes text src/lib/db/schema.ts:185
}
// plus leftJoin clients.name + projects.title in GET github case
// src/app/api/assets/[category]/route.ts:174-193What linked gives you: client-filtered view where clientId=acme.id, project attribution projectId → projects title budget src/lib/db/schema.ts:183, searchable techStack text[] ["Next.js 16","Tailwind v4","Drizzle"], and credential adjacency — DEPLOY_TOKEN stays AES-256-GCM gcm:iv:tag:enc src/lib/vault/crypto.ts:22 with clientId/projectId src/lib/db/schema.ts:125, via hosting vaultItemId src/lib/db/schema.ts:198.
1Password / LastPass / Sheets vs RunoSO Vault + Assets
| Need | Sheets / Notion | 1Password / LastPass | RunoSO Vault+Assets | |
|---|---|---|---|---|
| Repo metadata | `Repo | Link` text, no enum | No repo concept — entry acme github unstructured | assetsGithub repoName, url, visibility enum, githubAccount, techStack[] typed + ALLOWED_CATEGORIES src/app/api/assets/[category]/route.ts:91 |
| Link to client/project | Manual Client text, breaks on rename | No linking; Collections ≠ clientId fk | clientId + projectId FK src/lib/db/schema.ts:182 — JOIN in API leftJoin(clients) src/app/api/assets/[category]/route.ts:190 | |
| Encrypted credentials | Plaintext in sheet — one share = leak | AES-256 but no asset link | vaultItems AES-256-GCM gcm:iv:tag:enc src/lib/vault/crypto.ts:28 + clientId/projectId src/lib/db/schema.ts:125 + hosting vaultItemId link | |
| Alerts | None — you remember expiry | No renewal alerts | Cron daily checks assetsDomains 14/7/3/1/0 src/app/api/cron/daily/route.ts:16 + RENEWAL_MILESTONES 7/3/1/0 for hosting/subs → notifications + email | |
| Handover | Copy-paste 5 tabs, miss one | Psst! link one password only | portalTokens src/lib/db/schema-public.ts:169 → share asset+vault bundle without login; client sees all repos in one view | |
| Cost | Free + 70h/yr hunting | $36/yr personal, $0 linked context | Free 5 assets/mo, Solo ∞ included + finance links |
The difference: 1Password encrypts a string. Sheets lists a link. RunoSO encrypts + links + alerts. Your repo knows its client, project, hosting IP and vault key — and tells you before anything expires.
The Workflow That Ends Repo Chaos
1. Audit in 15 minutes. GET /api/assets/github paginated buildPaginatedQuery. Add every githubAccount repo with visibility + techStack — most freelancers find 2 dead forks.
2. Link to client/project. POST githubPostSchema src/app/api/assets/[category]/route.ts:44 validates visibility enum; SELECT * WHERE clientId=? replaces Ctrl+F.
3. Connect hosting + vault. assetsHosting provider ipAddress vaultItemId src/lib/db/schema.ts:190 holds SSH token encrypted passwordEncrypted src/lib/db/schema.ts:130 — one query repo → hosting → vault.
4. Use techStack as portfolio. Filter contains Next.js 16 → 8 public repos ready to paste with clientName+projectTitle JOIN in AssetsPageClient.
Mistakes That Keep Repos Orphaned
No githubAccount. URL without owner → you won't know which token works at midnight. Always fill githubAccount. Empty techStack. Two tags (Next.js+Drizzle) takes 5s, saves 30min in proposals. No visibility. public|private decides what you can share — missing mark loses leads.
Stop managing repos in your head. Link every GitHub repo to its client, project, hosting and encrypted credential — one dashboard, zero hunt.
→ Organize Your Repos in RunoSO — Free
By Gautam Parmar — solo founder. Repos are not links, they are linked business assets.
Keep Reading
- Secure keys behind repos: Where freelancers should never store passwords.
- Vault deep dive: Password manager vs encrypted vault.
- Handover without misses: Digital asset handover template.
FAQ
How is this different from GitHub's own dashboard? GitHub shows repos, not business context. RunoSO adds clientId/projectId src/lib/db/schema.ts:182, techStack[], and joins to assetsHosting vaultItemId + encrypted vaultItems src/lib/vault/crypto.ts:22. GitHub knows code; RunoSO knows whose code and what it cost.
Can I store deploy tokens securely? Yes — tokens go in vaultItems passwordEncrypted AES-256-GCM gcm:iv:tag:enc src/lib/vault/crypto.ts:28 with clientId/projectId linkage. Hosting asset then references vaultItemId. Token never sits plaintext in asset notes.
What about handing off repos to clients? Use portalTokens src/lib/db/schema-public.ts:169 to share a client-scoped asset bundle — domains, hosting, GitHub repos, vault references — without giving vault plaintext. Client sees their 3 repos in one view, you keep credential control until transfer.



