Skip to content

About

Turn any GitHub profile into a deterministic, explainable 100-point engineering score and shareable GitHub Receipts. The AI writes the narrative, never the numbers.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

Skill Issue

Your GitHub profile is your real resume. Skill Issue reads it honestly.

Version License Live Status

Next.js React Tailwind FastAPI Python Neon Upstash Groq

▶ 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.

Skill Issue report for a public GitHub profile: a 73 of 100 aggregate score at the Senior Engineer tier, with the badges it earned


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.


What it does

🔍 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

The scoring rubric

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:

The scoring matrix on a live report: six signal cards showing points out of each maximum, with a Why breakdown under each


How it works

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 &amp; 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
Loading

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.


Status

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 /analyze for 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.tech domain cutover, tracked in docs/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 /analyze path (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 /me history with undo, a golden "creator" scorecard, and a first (incomplete) back-nav spinner fix.
  • v0.9.2 — rate limiting on /analyze and /narrative: per-IP for anonymous, higher per-user caps when signed in.
  • v0.9.1 — closed the /me N+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 /analyze designed for a p95 of at most 200 ms; not yet measured live).

Full detail in CHANGELOG.md; the roadmap lives in PLAN.md.


Documentation map

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

Quick start

Two terminals: the FastAPI backend and the Next.js frontend run side by side in dev.

Backend (:8000)

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 8000

On the LLM key: the client is OpenAI-compatible, so OPENAI_API_KEY is the variable name regardless of provider. Production points it at Groq (openai/gpt-oss-120b) via NARRATIVE_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/octocat

db reports DB reachability when DATABASE_URL is set. cache reports Upstash reachability; unconfigured is fine for local dev, the in-process fallback covers it.

Frontend (:3000)

cd frontend
npm install
NODE_OPTIONS=--max-old-space-size=2048 npm run dev

Raise the heap. Without --max-old-space-size=2048, next dev can 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.

Tests + lint

# 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 build

Backend tests use pytest + respx; the DB-dependent ones need TEST_DATABASE_URL (local Postgres or a Neon dev branch). Frontend tests run on Vitest.


License

MIT, see LICENSE.

About

Turn any GitHub profile into a deterministic, explainable 100-point engineering score and shareable GitHub Receipts. The AI writes the narrative, never the numbers.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages