Your GitHub profile is your real resume. Skill Issue reads it honestly.
▶ Try it live: skillissue.tech
Analyze any GitHub profile in seconds. Free, no signup required.
If it's useful, a ⭐ helps other devs find it.
Drop in a username. Skill Issue analyzes repositories, engineering maturity, OSS contributions, coding discipline, and growth trajectory, then turns it into actionable feedback, a 100-point engineering score, and a shareable "GitHub Receipt."
Engineering insight first, AI flavor second. Scoring is deterministic and explainable. The AI only writes the narrative, summaries, and jokes; it never invents a number.
| 🔍 Profile analysis | Pinned repos, contribution rhythm, README quality, CI/CD, deployment maturity, testing culture, licence detection |
| 💯 Engineering score | 100 points across six weighted signals: every point traceable to evidence, shown on each score card |
| 🪜 7-tier ladder | Hobbyist → Student Builder → Entry-Level → Professional → Senior → Staff → Principal, with intra-tier sub-rank |
| 🏅 Stackable badges | OSS Contributor, PR Master, Maintainer, Star Magnet, Polyglot, Long-haul, Indie Hacker, Toolmaker: deterministic and multi-earnable |
| 🔓 Tier-gated depth | Higher tiers unlock licence credit (Professional+), PR review depth (Senior+) and cross-repo breadth (Staff+). Licences, cross-repo breadth, README depth, dependency manifests and commit-message quality come from data every analysis already reads; CI workflows cost one batched query |
| 🔥 Two voices | Roast Mode for what a blunt senior would say · Mentor Mode for how to fix it |
| 🧾 GitHub Receipts™ | Shareable 1200×630 scorecards for LinkedIn, X, Discord, portfolios |
| ⚡ Fast on repeat | Warm /analyze/{user} is served from an Upstash Redis report cache, designed for a p95 of at most 200 ms; the live measurement is still pending |
| Signal | Points | Question it answers |
|---|---|---|
| Repo Quality | 30 | Do your repos look maintained: READMEs, tests, deploys, licences? |
| Engineering Maturity | 20 | Typed languages, CI pipelines, real architecture: not just scripts? |
| OSS & Collaboration | 15 | Do you ship into other people's codebases, or only your own? |
| Recruiter Signal | 15 | What a hiring manager sees first: profile README, pins, bio, links, stars |
| Consistency | 10 | Commit rhythm over months: momentum, not a single sprint |
| Learning Trajectory | 10 | Staying power: account age, new projects this year, activity year over year |
The same six signals on a live report, each card with its own "Why" breakdown:
Determinism first: the score is computed by code before any model is called, and the narrator is handed the finished Report — scores, tier, badges, headline signals — never the raw repos. It cannot invent a number it was never shown.
flowchart TD
U(["User enters a GitHub username"])
FE["<b>Next.js 16 · App Router</b><br/>landing · analyze flow · results · receipts<br/><i>renders facts, never computes a score</i>"]
subgraph BE ["FastAPI backend — Python 3.12, async end to end"]
direction TB
ING["<b>Ingestion</b> · httpx + GraphQL<br/>profile · pinned · repos · commits<br/>PRs · reviews · languages · contributions<br/><i>parallel, rate-limit aware, bounded fan-out</i>"]
P1["<b>Pass 1 — deterministic scoring</b><br/>repo quality 30 · maturity 20 · OSS 15<br/>recruiter signal 15 · consistency 10 · trajectory 10<br/>→ base total → tier"]
P2["<b>Pass 2 — tier-gated depth</b><br/>SPDX licence · PR review depth<br/>cross-repo breadth → re-score"]
LADDER["<b>Ladder & badges</b><br/>7 tiers, Hobbyist → Principal, with sub-rank<br/>8 stackable badges, no priority ordering"]
NARR["<b>Narrative</b> · Groq, mode-aware<br/>Roast or Mentor · streams over SSE<br/><i>sees the Report only</i>"]
ING --> P1 --> P2 --> LADDER --> NARR
end
subgraph CACHE ["Upstash Redis — four layers, every one fail-open"]
direction TB
L["A · report cache, 6 h TTL<br/>B · singleflight SET-NX lock<br/>C · GitHub API cache, per endpoint<br/>D · narrative cache + daily budget"]
end
GH[("GitHub REST + GraphQL")]
PG[("Neon Postgres<br/>users · sessions<br/>analyses + runs · narratives")]
OAUTH["GitHub OAuth<br/>sign-in + higher rate limits"]
OG["1200×630 GitHub Receipt<br/>/u/[user]/card · /share/[slug]"]
U --> FE -->|"HTTP"| ING
GH -.->|"REST + GraphQL · cached per endpoint"| ING
ING <--> CACHE
P1 --> CACHE
NARR -->|"SSE stream"| FE
LADDER --> PG
OAUTH --> FE
FE --> OG
classDef det fill:#064e3b,stroke:#10b981,stroke-width:2px,color:#d1fae5
classDef ai fill:#312e81,stroke:#818cf8,stroke-width:2px,color:#e2e8f0
classDef store fill:#1e293b,stroke:#475569,stroke-width:1.5px,color:#cbd5e1
class P1,P2,LADDER det
class NARR ai
class GH,PG,L,OAUTH,OG store
Green is the part that must be right, and is pure: same GitHub data in, same score out, every point carrying its evidence. A warm /analyze is answered from layer A, designed for a p95 of at most 200 ms (the live measurement is still pending); if Redis is down, all four layers degrade to a slower but correct answer rather than an error.
v1.0.17: live at skillissue.tech, with GitHub OAuth sign-in, Neon Postgres persistence, /me history, and opt-in /share/[slug] public links.
Following the v1.0.0 stable launch, a security-hardening line ran from a full internal audit through v1.0.8, and CI-integrity work through v1.0.10. v1.0.11 closed a navigation-state bug sweep that traced four separate reports back to one root cause. v1.0.14 reworked scoring after a full audit against how developers work in 2026, and v1.0.15 reads commit activity from GitHub's contribution data, so work in organisations' and other people's repositories counts. v1.0.16 made the privacy contract hold: no cookie, token, secret or IP reaches Sentry, and PostHog stores no IP. v1.0.17 patched two critical Next.js advisories for remote code execution, along with DOMPurify and the backend's certificate bundle.
| Release | What shipped |
|---|---|
| v1.0.17 | Dependency advisories: Next.js 16.4.3 closes two critical remote-code-execution advisories; DOMPurify 3.4.17 and certifi 2026.10.23 are patched alongside, with no score changes |
| v1.0.16 | Privacy patch: Sentry receives no cookies, tokens, secrets, IPs, OAuth values or request bodies from errors or transactions, PostHog stores no IP and records no sessions, and the shadcn CLI behind two dev alerts is gone |
| v1.0.15 | Commit activity from GitHub's contribution data: public commits in organisations' and other people's repos count toward Consistency, the repos you push to get inspected first, and a fallback that says what it counted |
| v1.0.14 | Scoring audit: open-source credit only for PRs merged into other people's repos, a rebuilt Recruiter Signal, licence and README checks that no longer penalise large portfolios, evidence on every score card, fresh analyses in about half the time |
| v1.0.13 | Maintenance: two critical Next.js advisories closed, sign-ins and saves confirmed before the server answers, history refresh reads fresh GitHub data |
| v1.0.12 | Narrator back online on Groq's openai/gpt-oss-120b after the old model's retirement, with an alert when it falls back |
| v1.0.11 | Navigation-state bug sweep: the narrative no longer duplicates on back-nav, /me reflects saves immediately, badge evidence is reachable by screen reader, and a version-drift guard now fails the build |
| v1.0.10 | Dependency-manifest drift guard: CI fails if pyproject.toml / uv.lock / requirements.txt disagree |
| v1.0.9 | Audit-gate resilience: an advisory-registry outage warns instead of hard-blocking every PR |
| v1.0.8 | Auth & endpoint hardening: session ids hashed at rest, Origin check on mutations, promotable CSP, security.txt + PR dependency review |
| v1.0.7 | Version-display fix + low-severity hardening: secret repr-scrub, CORS-wildcard boot guard, cron-log trim, SSE done-sentinel |
| v1.0.6 | Shared-token quota breaker: sheds new anonymous analyses before the shared GitHub token is exhausted |
| v1.0.5 | Ingest amplification containment: per-analysis GitHub-call cap, request deadlines, LLM-budget refund on client abort |
| v1.0.4 | Fail-closed cost controls: per-subject LLM budget, spoof-proof client IP, Sentry secret scrubbing, CI least-privilege |
Earlier history (v0.1.0 → v1.0.3)
- v1.0.3 — hotfixed
/analyzefor hyper-active accounts tripping GitHub's GraphQL cost limit. - v1.0.2 — security & hardening: fixed the nightly refresh cron (Vercel fires GET; the handler was POST-only), patched 7 backend dependency CVEs, added CSRF, supply-chain (Dependabot + CI SCA gate) and HTTP-header hardening.
- v1.0.1 — operational launch-ops milestone: the
skillissue.techdomain cutover, tracked indocs/LAUNCH.md. - v1.0.0 — first stable release: homepage link-preview cards, autofocused search, inline "analyze another" on reports, repo cleanup.
- v0.9.8 — launch landing sections: example reports, a how-it-works methodology section, a GitHub-star CTA.
- v0.9.7 — Privacy Policy + Terms of Service, linked from a new site-wide footer.
- v0.9.6 — reusable load-test harness for the warm
/analyzepath (the full 100 RPS run is an operator step). - v0.9.5 — full pre-launch security audit (no high/critical findings), OAuth scope tightened to
read:user, HTTP security headers. - v0.9.4 — DB connection pool size made env-tunable (defaults unchanged; RUM showed no pool exhaustion) and the real back-nav spinner fix.
- v0.9.3 — deletable
/mehistory with undo, a golden "creator" scorecard, and a first (incomplete) back-nav spinner fix. - v0.9.2 — rate limiting on
/analyzeand/narrative: per-IP for anonymous, higher per-user caps when signed in. - v0.9.1 — closed the
/meN+1 and added per-namespace Report cache versioning. - v0.9.0 — opened Beta hardening with bounded GitHub fan-out.
- v0.8.7 — modernized project config (
vercel.json→vercel.ts). - v0.8.6 — closed v0.7.1's deferred share-page caching.
- v0.8.5 — closed the post-deploy-Sentry loop with a pre-merge CI gate.
- v0.8.4 — fixed the silent narrative misattribution.
- v0.8.3 — hotfixed the empty-repo crash.
- v0.8.2 — manual force-refresh button on
/me. - v0.8.1 — nightly cron with bearer auth.
- v0.8.0 — Sentry (FE+BE), PostHog (events + web vitals), structlog JSON logging, on-voice 404, full axe a11y pass.
- v0.7.2 — prod-certified the perf budget (CLS 0.080 → 0 structurally, perf 90 → 94, LCP 2,804 → 2,773 ms).
- v0.7.0 — Upstash Redis caching (warm
/analyzedesigned for a p95 of at most 200 ms; not yet measured live).
Full detail in CHANGELOG.md; the roadmap lives in PLAN.md.
| File | Purpose |
|---|---|
PLAN.md |
Versioned roadmap: what ships in each slice |
CHANGELOG.md |
What has actually shipped, per Keep-a-Changelog |
AGENTS.md |
Required reading for every AI agent or human contributor: the rules of engagement |
ARCHITECTURE.md |
System design + MCP ecosystem |
docs/PRODUCT_VISION.md |
Personality, target users, scoring rubric, voice |
docs/TECH_STACK.md |
Every library, version pin, and why |
docs/PROGRESS_LOG.md |
Running narrative log: what was done and why |
docs/DEPLOY.md |
How to ship to Vercel (multi-service project + Upstash + Neon walkthrough) |
docs/OBSERVABILITY.md |
Sentry, PostHog, structlog: what's wired and what to watch |
docs/superpowers/plans/ |
TDD sub-plans for each version slice |
Two terminals: the FastAPI backend and the Next.js frontend run side by side in dev.
cd backend
uv sync
cp .env.example .env # then add your GITHUB_TOKEN and OPENAI_API_KEY
uv run uvicorn app.main:app --reload --port 8000On the LLM key: the client is OpenAI-compatible, so
OPENAI_API_KEYis the variable name regardless of provider. Production points it at Groq (openai/gpt-oss-120b) viaNARRATIVE_BASE_URL+NARRATIVE_MODEL; leave both unset to use OpenAI directly. The narrative layer is optional, scoring works without any LLM key.
Verify:
curl http://localhost:8000/health
# {"status":"ok","version":"1.0.17","db":"up","cache":"unconfigured"}
curl http://localhost:8000/analyze/octocatdb reports DB reachability when DATABASE_URL is set. cache reports Upstash reachability; unconfigured is fine for local dev, the in-process fallback covers it.
cd frontend
npm install
NODE_OPTIONS=--max-old-space-size=2048 npm run devRaise the heap. Without
--max-old-space-size=2048,next devcan OOM-crash on a cold compile.
The frontend reads NEXT_PUBLIC_BACKEND_URL from frontend/.env.local (defaults to http://localhost:8000). Open http://localhost:3000 and analyze a username.
# backend: DB-fixture tests skip without TEST_DATABASE_URL
cd backend && uv run ruff check . && uv run ruff format --check . && uv run pytest -q
# frontend
cd frontend && npm run lint && npx tsc --noEmit && npm run test:run && npm run buildBackend tests use pytest + respx; the DB-dependent ones need TEST_DATABASE_URL (local Postgres or a Neon dev branch). Frontend tests run on Vitest.
MIT, see LICENSE.

