Priyanshu OS / AI Voice Portfolio
A portfolio you talk to. An AI agent grounded in structured profile data that can answer, navigate and reason about fit.
Case study · Working MVP: deployed on its own domain, and you are reading it

The idea
Replace the static resume with an agent that answers questions about Priyanshu's background, navigates this site, surfaces relevant work, and analyses a pasted job description against his actual experience.
Why I wanted to build it
Resumes flatten a non-linear path into bullet points. Recruiters and hiring managers have specific questions, and a static page cannot answer them or admit what it does not know.
Product philosophy
- Grounded, not generative
- Every answer derives from /data/*.json. The agent is instructed to say when something is not in the data rather than fill the gap.
- Gaps are a feature
- The relevance mode reports missing experience explicitly. A match list without gaps is not trustworthy.
- Actions over prose
- The agent can navigate the page and highlight dimensions through tool calls, so an answer is also a demonstration.
Fig. 2Activate, follow, pause, save, leave, come back.
- 1Land
Fig. 1 plots the career as a curve. The ask input is drawn on the plot as an annotation, not bolted on as a chat bubble.
- 2Ask
The question goes to a system prompt built from the same six JSON files the page itself renders from.
- 3Answer
The reply arrives in the margin, in third person, and says plainly when something is not on record.
- 4Act
Validated actions move the page: scroll to a section, hatch the relevant tracks, open a case study.
- 5Check fit
Paste a job description. Every claimed match must cite a dataset id, and an uncited one is dropped rather than shown.
- 6Read the gaps
Missing experience comes back as output, next to the matches, instead of being left out.


Table 1Decisions, and what they cost.
| Decision | Tradeoff accepted |
|---|---|
| The data is the source of truth, not the components | Every section and every AI answer renders from six JSON files, so the page and the agent can never disagree. A copy fix needs a deploy, which is the price of there being one version of the truth. |
| Grounded, not generative | The prompt forbids invention and requires "that is not something I have on record". It refuses questions a looser agent would happily answer, which is the point: a portfolio agent that guesses is worse than no agent. |
| Gaps are output, not omission | The fit check returns missing experience alongside the matches, so the site argues against its own candidate in writing. A fit report with no gaps is not trustworthy. |
| One model provider was a single point of failure | OpenRouter withdrew the free model this site ran on and the AI went down until it was noticed. Five free models failed five different ways in one afternoon: withdrawn, rate limited, upstream overloaded, restricted to other clients, and answering 200 then 503 a minute later. The fix was a chain across four providers with a circuit breaker rather than a better single provider. Writing it surfaced a subtler bug: the first version treated any 4xx as fatal, which is wrong, because Google answers 400 to a bad API key and Groq answers 413 to a prompt Cerebras accepts. A sabotage test caught it before it shipped. |
| The prompt is sized to the provider | Groq's free tier allows 8,000 tokens a minute against a full prompt of about 10,000, so it is sent a lean knowledge base measured at 5,993 tokens against its own tokenizer. A fallback answers with less depth on project internals. A thinner answer beats no answer. |
| The model routes are rate limited | Two public endpoints on a free-tier key are an open proxy for anyone who finds them, so both are capped per visitor and per day. A genuinely curious visitor can hit a wall, and the figures and notes all still work without the AI. |
- q1Still open: Rate-limit counters live in the running instance, so the daily cap is a brake rather than a guarantee if the platform runs several. Is a shared store worth the dependency at this size?
- q2Still open: There is no conversation memory. Should a visitor be able to pick up where they left off, or is a stateless agent the more honest demonstration?
- q3Still open: Voice quality is whatever the browser ships, which varies a lot by platform.
- q4Still open: A free provider can withdraw a model at any time. The chain turns that into a slower answer instead of an outage, but it does not remove it.
Fig. 5Technical architecture
- Next.js 15 (App Router) and TypeScript, Tailwind v4, self-hosted OFL fonts
- Four OpenAI-compatible providers tried in order (Cerebras, Gemini, OpenRouter, Groq), with a five-minute circuit breaker and a per-attempt timeout
- Per-provider prompt sizing: a provider with a smaller token allowance is sent a smaller knowledge base
- Structured JSON output for UI actions, validated against known section, dimension and project ids before anything runs
- In-memory rate limiting on both model routes, with the daily provider budget split between them
- Web Speech API for voice in and out, d3-force for the knowledge graph, Motion for one authored motion grammar
Where AI fits
Central. This is a tool-using agent with grounding, structured outputs and explicit gap reporting. Its limits are also documented: no persistent memory, browser-native voice quality, and dependence on free-tier model rate limits.
Works today
- ✓Grounded chat with structured UI actions, validated against known ids before the client runs them
- ✓Job-description fit check with cited matches, transferable experience and explicit gaps
- ✓Four-provider failover chain with a five-minute circuit breaker and per-attempt timeouts
- ✓Per-provider knowledge-base tiers, so a small token budget gets a prompt built to fit it
- ✓An offline provider benchmark that races the real dataset and reports latency, success rate and JSON compliance
- ✓Rate limiting on both model routes, with the daily budget split between them
- ✓Two renditions of one world, keyboard access to every figure, and a reduced-motion path
Roadmap (planned, not claimed)
- ○Hybrid retrieval over the same JSON, so a question retrieves what it needs instead of sending the whole dataset every time
- ○A labelled question set and a scoring harness, so retrieval quality is measured rather than asserted
- ○Per-project OG images for the case studies
What it says, without saying it
Grounding and refusal: answers derive from a dataset, and the agent says when the dataset does not cover the question Structured outputs treated as untrusted: every UI action is validated against known ids before it runs, and the job description is data, never instructions Operating on infrastructure you do not control: failover, circuit breaking, prompt budgets per provider, and a benchmark to decide the order Honesty as a product decision: statuses that do not overclaim, and a fit report that reports its own gaps
Related tracks: Builder, Agents, Product · see Fig. 2