A tech reading feed ranked to your skills — powered by Jev.
Skillfeed pulls today’s writing from Hacker News, Dev.to, Hashnode, and Lobsters, then scores each piece against a short summary of what you know and care about. You pick the platforms, describe your skills once, and get the best matches first.
Jev (typesafe-ai/jev) is TypeSafe AI’s System One model: it evaluates a state against typed questions and returns scores and probabilities your app can use directly.
In Skillfeed that looks like this:
- State — your skill summary (and optional avoid list) plus a batch of article metadata (title, description, tags).
- Questions — one
scorequestion per article: how well does this match the user’s skills? (poor → excellent rubric). - Answers — calibrated skill-match scores. Skillfeed sorts the feed by those scores.
We call Jev through the Vercel AI SDK’s experimental_evaluate API on AI Gateway. Articles are scored in batches (UI default: 7) so each request stays under the model’s 32K context window. Multiple questions in one request are evaluated together, which keeps ranking fast and cheap compared with generating long text for every article.
More background: Building a Harness with Jev (LangChain).
- Jev skill matching — poor → excellent score rubric against your summary
- Platform multi-select — include only the sources you care about
- Parallel metadata fetch — titles, descriptions, tags (no full-page scrape)
- Batched evaluate — keeps each call under ~32K tokens (UI default: 7 articles)
- SSE progress UI — smart loading with live source counts
- Provider adapter — swap evaluation backends via factory
- Dark-first UI — source icons, ranked list, GitHub link in header
| Layer | Choice |
|---|---|
| App | Next.js 16 (App Router) |
| UI | React 19, Tailwind CSS 4 |
| Ranking | Jev via AI SDK experimental_evaluate + AI Gateway |
| Validation | Zod |
| Progress | Server-Sent Events (text/event-stream) |
| Hosting | Vercel (frontend + API together) |
- Node.js 20+
- A Vercel AI Gateway API key
git clone https://github.com/iikareem/skillfeed.git
cd skillfeed
npm installcp .env.example .env.localAI_GATEWAY_API_KEY=your_ai_gateway_api_key_here
# Optional — defaults to vercel-gateway
EVALUATION_PROVIDER=vercel-gateway
EVALUATION_PROVIDERis an app setting (which adapter to use), not a Vercel dashboard field. Today the only value isvercel-gateway.
AI Gateway may require a payment method to unlock free credits. Successful requests only.
npm run devOpen http://localhost:3000.
The UI and backend (/api/rank, /api/sources) are the same Next.js project — one deploy covers both.
- Import iikareem/skillfeed in Vercel.
- Set
AI_GATEWAY_API_KEYin Project → Settings → Environment Variables. - Deploy.
Or from the CLI:
npx vercel
npx vercel env add AI_GATEWAY_API_KEY
npx vercel --prodLive: skillfeed-xi.vercel.app
┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ ┌────────┐
│ User profile │ ──▶ │ Fetch sources│ ──▶ │ Score in batches│ ──▶ │ Sort │
│ + platforms │ │ (parallel) │ │ experimental_ │ │ by score│
└──────────────┘ └──────────────┘ │ evaluate (Jev) │ └────────┘
└─────────────────┘
- Collect — up to
perSourcefrom each selected platform, deduped, capped atmaxArticles. - Batch — chunk articles (default UI: 7 per call) for the 32K context window.
- Score with Jev — typed
scorequestions againststate.profile. - Sort — highest skill-match first.
Progress streams over SSE so the UI never sits on a blank spinner.
Streams Server-Sent Events. Last event is always complete or error.
Request body
{
"profile": {
"summary": "Senior fullstack — TypeScript, Next.js, AI SDK, Postgres.",
"avoid": "Crypto hype, engagement bait, no-code tutorials"
},
"sources": ["hacker-news", "devto"],
"perSource": 12,
"maxArticles": 28,
"batchSize": 7
}| Field | Required | Description |
|---|---|---|
profile.summary |
yes | Skills / interests (min 8 chars) |
profile.avoid |
no | Topics to penalize |
sources |
no | hacker-news, devto, hashnode, lobsters (default: all) |
perSource |
no | Articles per platform (default 15) |
maxArticles |
no | Cap after dedupe (default 40) |
batchSize |
no | Articles per evaluate call (default 8) |
Example
curl -N https://skillfeed-xi.vercel.app/api/rank \
-H 'Content-Type: application/json' \
-d '{
"profile": {
"summary": "Senior fullstack — TypeScript, Next.js, AI SDK.",
"avoid": "Crypto hype"
},
"sources": ["hacker-news", "devto"],
"batchSize": 7
}'SSE stages: fetching → fetched → scoring → sorting → complete | error
Debug metadata fetch (no ranking).
curl 'https://skillfeed-xi.vercel.app/api/sources?limit=10&source=devto'src/
├── app/
│ ├── api/rank/ # SSE ranking endpoint
│ ├── api/sources/ # Metadata debug endpoint
│ └── page.tsx # Skillfeed UI
├── components/
│ └── source-mark.tsx # Source icons + platform picker
├── sources/ # One fetcher per platform
├── evaluation/ # Provider interface + Vercel adapter
├── ranking/ # Collect → score → sort
└── lib/ # env, http, chunk helpers
- Sources never know about AI — metadata only.
- Evaluation is swappable via
EvaluationProvider+ factory. - Ranking owns the pipeline; the HTTP route only encodes SSE.
npm run dev # Local development
npm run build # Production build
npm run start # Run production server
npm run lint # ESLint| Variable | Required | Description |
|---|---|---|
AI_GATEWAY_API_KEY |
yes | Vercel AI Gateway API key |
EVALUATION_PROVIDER |
no | Adapter id — default vercel-gateway |
Never commit .env.local. Use .env.example.
See CONTRIBUTING.md for local setup and PR expectations.