JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 42
  • Score
    100M100P100Q73952F
  • License MIT

Your portfolio answers questions. Define a KB, render a live persona.

Package Exports

  • livecv
  • livecv/styles.css
  • livecv/theme.css

Readme

livecv

Your portfolio answers questions. Define a KB, render a live persona.

livecv turns a typed config + markdown KB into a generative-UI personal site. Visitors type a question, an LLM picks components from a Zod-typed catalog, and the page renders bespoke per query.

Install

npm install livecv @ai-sdk/anthropic @ai-sdk/react ai \
  @json-render/core @json-render/react @json-render/shadcn \
  motion lucide-react zod

The four files you write

my-portfolio/
├── livecv.config.ts       — typed config (identity, career, projects, blog, model)
├── content/kb.md           — prose KB (voice, principles, what you're focused on)
├── app/page.tsx            — <PersonaSite config={config} />
└── app/api/generate/route.ts — export const POST = createHandler({ config })

Minimum example

// livecv.config.ts
import fs from "node:fs";
import path from "node:path";
import { defineConfig } from "livecv";

export default defineConfig({
  identity: {
    name: "Jane Doe",
    role: "Software Engineer",
    bio: "...",
    email: "jane@example.com",
    links: { github: "https://github.com/janedoe" },
  },
  career: [
    { start: "2024", end: "Present", title: "Senior Engineer", org: "Foo",
      detail: "...", tech: ["TypeScript"], status: "current" },
  ],
  projects: [
    { id: "thing", title: "thing", tldr: "...", description: "...",
      tech: ["TypeScript"], cluster: "tools",
      howItWorks: ["..."], keyInsight: "..." },
  ],
  clusters: [{ id: "tools", label: "Tools" }],
  blog: [],
  kbContent: fs.readFileSync(path.join(process.cwd(), "content/kb.md"), "utf-8"),
  model: "claude-haiku-4-5",
});
// app/page.tsx
"use client";
import { PersonaSite } from "livecv";
import config from "@/livecv.config";

export default function Page() {
  return <PersonaSite config={config} />;
}
// app/api/generate/route.ts
import { createHandler } from "livecv/handler";
import config from "@/livecv.config";

export const POST = createHandler({ config });
export const maxDuration = 60;
/* app/globals.css */
@import "tailwindcss";
@import "livecv/styles.css";  /* pre-compiled utility CSS for livecv components */
@import "livecv/theme.css";   /* CSS variable tokens */

livecv ships its own pre-compiled Tailwind utility CSS (dist/styles.css, ~44KB) generated by scanning the package's compiled components at build time. That means consumers don't need an @source directive pointing at node_modules — the utilities used by livecv components are guaranteed to be in the final bundle through a normal package import.

# .env.local — in your Next.js app (see .env.local.example in this repo)
ANTHROPIC_API_KEY=sk-ant-...

That's it. npm run dev and you have a live persona portfolio.

See .env.local.example for the full list of env vars (just ANTHROPIC_API_KEY is required; the rest are optional).

What renders

The LLM picks from this catalog per question:

  • ProfileBlock — your card with name/role/links
  • CareerTimeline — chronological rail with patent + education, supports a focus prop to dim/highlight rows by topic
  • ProjectGrid — your projects, filtered by cluster, with "more on GitHub" footer
  • ProjectDeepDive — full breakdown of one project
  • TechStack — tag cloud sized by frequency
  • BlogList / BlogPostCard — your writing
  • PrincipleList — your engineering principles (only for philosophy questions, never for experience)
  • LeadershipStories — STAR-format experience stories, generated fresh per question
  • ProofPoints — tag + claim + evidence rows for hire-style answers
  • PersonalNote — one-sentence first-person opener, always freshly generated
  • Callout / Text / Link — prose primitives

Project IDs, blog slugs, and cluster IDs become Zod enums automatically — the LLM cannot hallucinate references that don't exist. Bad specs fail validation; the renderer falls back gracefully.

Theme

Override any CSS variable in your own globals.css:

:root {
  --lc-foreground: #000;
  --lc-background: #fff;
  /* ... */
}

Dark mode is the .dark class on <html> (or anywhere up the tree).

Status

v0.1 — works for a single user portfolio. Not yet:

  • Custom component overrides (slot system)
  • Multi-tenant
  • Edge runtime
  • Rate-limit / abuse protection (use Upstash separately for now)

Reference

The reference implementation is ai.sayantan.sh — its source consumes this package via a file: reference and supplies only its own config + KB.