Introduction#
GitHub has a small, under-used feature: create a public repository with the exact same name as your username, and the README.md inside it gets rendered at the top of your profile page — before your pinned repos, before anything else. It’s the closest thing GitHub gives you to a personal landing page, and most people leave it either empty or filled with a stock template.
This post walks through building one styled as a Linux terminal session — a whoami, a cat about.md, a skills listing — with genuinely dynamic content underneath: repo counts, per-project stars, contribution streaks, and a visitor counter that update themselves with zero maintenance, no personal access token, and no server of your own.
One important expectation to set upfront: a GitHub profile README is static markdown — GitHub strips out all <script> tags, so you cannot build a literally interactive terminal where typing whoami triggers a real command. What you can build is something that convincingly looks like a terminal session, with the “dynamic” parts being live-updating images, not live-executing code. That distinction matters and is worth understanding before you start.
Step 1: Create the Special Repository#
- Go to
github.com/new - Name the repository exactly your username (case-sensitive match)
- Set it to Public — private doesn’t render on your profile
- Skip the README initialization — you’ll push your own
GitHub confirms it worked with a banner on the empty repo: "your-username/your-username is a special repository."
Step 2: The Trick Behind “Dynamic” Content in Static Markdown#
Since a README can’t run code, every “live” element here is actually an image — an SVG generated on-the-fly by a small web service every time GitHub (or a browser) requests it. The two techniques used throughout:
shields.io dynamic JSON badges#
shields.io can fetch a JSON document and render one field from it as a badge, generated fresh on each request (cached briefly):
https://img.shields.io/badge/dynamic/json?url=<json-endpoint>&query=$.<field>&label=<label>&color=<hex>
Pointed at GitHub’s own public API, this gives you a badge that always reflects reality with no code of your own running anywhere:

api.github.com/users/your-username returns a JSON object with public_repos, followers, following, etc. — swap the query field to show any of them. The same trick works per-repository against api.github.com/repos/your-username/your-repo for star count and primary language:

Create a new repo tomorrow, and the public-repo-count badge shows the new number the next time someone loads your profile — no workflow, no secret, no cron job.
Third-party stat-card generators#
A handful of community projects run a small server that draws an SVG card from your public GitHub activity on each request:
| What it shows | Service |
|---|---|
| Current/longest contribution streak | streak-stats.demolab.com/?user=your-username |
| Daily contribution graph | github-readme-activity-graph.vercel.app/graph?username=your-username |
| Tech stack icon row | skillicons.dev/icons?i=py,js,docker,... |
| Typing/rotating headline text | readme-typing-svg.demolab.com/?lines=... |
| Profile visit counter | komarev.com/ghpvc/?username=your-username |
None of these need authentication for public data — you just embed the URL as an <img> and the service does the work.
Step 3: A Gotcha Worth Knowing — Public Instances Go Down#
While building this, two of the most commonly recommended widgets turned out to be broken: the main stats/top-languages card at github-readme-stats.vercel.app returned DEPLOYMENT_PAUSED, and the trophy case at github-profile-trophy.vercel.app returned Payment required / DEPLOYMENT_DISABLED.
This isn’t a one-off — both projects explicitly warn about it in their own docs:
“The public Vercel instance is best-effort and can be unreliable due to rate limits and traffic spikes.”
These are extremely popular projects (tens of thousands of profiles embed them), so the shared free-tier hosting periodically gets rate-limited or paused entirely. Always test the actual image URL in a browser or with curl before committing it to your README — a broken <img> tag on your professional profile page looks worse than not having the section at all.
curl -s -o /dev/null -w "%{http_code}\n" "https://github-readme-stats.vercel.app/api?username=your-username"
# 503 -> don't ship it
If you want those specific widgets and can’t rely on the shared instance, both projects support deploying your own copy to your personal free Vercel account in a few clicks, which isolates you from everyone else’s traffic:
- Stats card:
github.com/anuraghazra/github-readme-stats→ “Deploy on your own” - Trophy case:
github.com/ryo-ma/github-profile-trophy→ “Deploy your own instance”
For this build, I skipped both and leaned on the widgets that were actually confirmed live (streak stats, activity graph, skill icons, shields.io, visitor counter) — a “stunning” profile that’s actually up beats a more elaborate one with broken images.
Step 4: Structuring It Like a Terminal Session#
The “terminal” feel comes entirely from formatting, not functionality — fenced code blocks with a fake prompt line, followed by the “output” as plain text in the same block:
```bash
you@github:~$ whoami
Your Name
Your role — your focus areas
```
Repeating this pattern for whoami, cat about.md, ls skills/, and cat contact.txt gives a consistent, scannable rhythm, with the dynamic badges/cards dropped in after each “command” as if it were the command’s real output:
### `$ ./repo-stats.sh --live`
<img src="https://streak-stats.demolab.com/?user=your-username&theme=dark&hide_border=true" />
<img src="https://github-readme-activity-graph.vercel.app/graph?username=your-username&theme=tokyo-night&hide_border=true" width="100%" />
A monochrome-green accent color (#39FF14) on the badges and typing banner reinforces the terminal look without needing any custom CSS — GitHub-flavored markdown doesn’t allow <style> blocks either, so color has to be pushed through each service’s own color= parameter.
Step 5: Native Pinning, Not Just README Links#
GitHub separately lets you pin up to 6 repositories so they render as cards directly on your profile, above or below the README depending on theme — go to your profile → Customize your pins. This is worth doing in addition to linking projects in the README, since pinned repos show live star/fork counts and a language color bar without any markdown at all.
Step 6: Private Repo Counts (Optional, More Setup)#
The shields.io trick above only works for public data — api.github.com/users/<you> never reveals private repo counts to an unauthenticated request, by design. If you want a “Public: 12 · Private: 8” style badge, that requires:
- A GitHub Personal Access Token with
reposcope - Stored as an encrypted Actions secret in your profile repo (never in the README or committed anywhere)
- A small scheduled GitHub Action that runs a script authenticated with that token, computes the counts, and rewrites a marked section of
README.md, then commits
This is meaningfully more setup than the zero-token approach above, and it’s the only place a secret enters the picture at all — everything else in this build is 100% public data through public endpoints.
Conclusion#
A GitHub profile README earns its “dynamic portfolio” reputation almost entirely from a handful of small, free, public image-generating services — not from anything running on your own infrastructure. The real engineering judgment is in:
- Verifying every embedded URL actually resolves before shipping — popular free-tier widgets go down more often than their star counts would suggest
- Choosing shields.io + GitHub’s own API wherever possible, since both are far more reliable than any third-party clone
- Accepting that “dynamic” here means live-rendered image, not interactive terminal — and designing the terminal illusion around formatting rather than fighting markdown’s lack of JavaScript
The result is a profile page that updates its repo counts, star counts, and contribution streaks forever, without a single scheduled job to maintain.
