NextRole πŸš€

✨ GenAI-Accelerated Career Advancement ✨

Upload your CV + a job description. Get a tailored resume PDF, a researched interview-prep doc, and a day-of battlecard cheat sheet β€” built by a multi-agent system with long-term memory.

Python Next.js React License: MIT PRs Welcome GitHub stars

LangChain LangGraph DeepAgents LangSmith Exposes MCP + A2A


What is NextRole?

Preparing for an interview takes hours of tedious resume tailoring and company research. NextRole automates the heavy lifting. Hand it your current CV and a target Job Description (or just a JD URL) β€” whether you're applying externally or angling for an internal move β€” and a team of specialized AI agents researches the company, rewrites your resume to fit, coaches you round-by-round, and prints a cheat sheet for the day of.

  • πŸ“„ Tailored resume β†’ PDF β€” your experience rewritten against the exact JD + company research, rendered with rendercv (editable & re-renderable).
  • πŸ” Deep company & role recon β€” live web research distilled into a match analysis.
  • 🎯 Structured interview prep β€” a self-introduction plus per-round STAR stories mapped to the role.
  • ⚑ Day-of battlecard β€” a one-page-per-round PDF cheat sheet for the final high-pressure review.
  • πŸ—“οΈ Time-boxed prep plans β€” a study plan that fits 1 month, 2 weeks, or just 3 hours.
  • πŸ”— Paste a JD URL β€” point it at a careers page; it extracts and processes the posting for you.
  • πŸ’¬ Iterate by chatting β€” "add a 4th round", "add React to my skills" β€” streaming multi-turn edits, with the right agent owning each file.
  • πŸ—‚οΈ Built-in workspace β€” upload, preview (PDF / MD / YAML / JSON / code), print-to-PDF, and swap the LLM at runtime.

Demo

▢️ Watch the full walkthrough in HD on YouTube Β»

Quick Start

The whole stack β€” frontend, backend, Postgres, Redis, S3-compatible object storage β€” runs in Docker.

# 1. Clone & configure
git clone https://github.com/tam159/next-role.git
cd next-role
cp .env.example .env          # then fill in your API keys (see table below)

# 2. Launch everything
docker compose up -d

# 3. Find your host ports (set in .env, vary per machine)
docker ps                     # read the 0.0.0.0:<host>->... mappings

# 4. Open the app
#    Frontend UI      β†’  http://localhost:<FRONTEND_LOCAL_PORT>/
#    Backend API docs β†’  http://localhost:<LANGGRAPH_LOCAL_PORT>/docs

πŸ’‘ Pick your LLM in the app. Open the in-app Configuration dialog to set the main agent and subagent models β€” no rebuild needed. See LLM configuration below for recommended models and free / local options.

Variable Required Purpose
OPENAI_API_KEY βœ… Default main + subagent models
TAVILY_API_KEY βœ… Web research (hiring-recon)
LLAMA_CLOUD_API_KEY βœ… Document parsing (LlamaParse)
POSTGRES_PASSWORD βœ… Local Postgres password
ANTHROPIC_API_KEY / GOOGLE_API_KEY ⬜ Alternative providers (swap at runtime)
OPENAI_API_BASE ⬜ Self-hosted / Azure / LM Studio endpoint
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_DEFAULT_REGION ⬜ AWS Bedrock models
LANGCHAIN_API_KEY + LANGCHAIN_TRACING_V2=true ⬜ LangSmith tracing (recommended)
AUTH_ENABLED / BETTER_AUTH_SECRET / LANGGRAPH_AUTH ⬜ Multi-user auth (opt-in) β€” steps in Authentication & multi-user
FRONTEND_LOCAL_PORT / LANGGRAPH_LOCAL_PORT / POSTGRES_LOCAL_PORT / REDIS_LOCAL_PORT / OBJECT_STORE_LOCAL_PORT preset Host port mappings
OBJECT_STORE_* preset Artifact object storage β€” see below

Object storage. Binary artifacts (uploads + rendered PDFs) live in S3-compatible object storage. Locally that's the compose object-store service (SeaweedFS) and the presets work as-is: S3 API on OBJECT_STORE_LOCAL_PORT, a browsable bucket UI on OBJECT_STORE_UI_LOCAL_PORT, and placeholder credentials that the local emulator accepts but doesn't enforce. For the cloud, point OBJECT_STORE_ENDPOINT / OBJECT_STORE_BUCKET / credentials at a managed bucket β€” AWS S3, GCS, Azure, or any S3-compatible store β€” with no code changes. Note: the AWS_* variables are reserved for Bedrock models; the object store reads only OBJECT_STORE_*.

Secrets live only in .env (gitignored); gitleaks runs on every commit.

Models are swappable at runtime β€” no rebuild. Open the in-app Configuration dialog and set Main agent / Subagents to a <provider>:<model> string (e.g. anthropic:claude-sonnet-5); leave blank to use the defaults. Settings persist in your browser's local storage.

Recommended: Claude Sonnet 5, GPT-5.x, or Gemini 3.x β€” e.g. anthropic:claude-sonnet-5, openai:gpt-5.6-terra, google_genai:gemini-3.5-flash.

Run it for free or fully local:

  • Tavily and LlamaCloud both include a generous monthly free tier β€” plenty for local use.
  • Google AI Studio offers a free tier for Gemini flash / lite models.
  • Fully local β€” point OPENAI_API_BASE at LM Studio or Ollama (both expose an OpenAI-compatible API) and fill your local model in the UI.

Output quality tracks the model you pick β€” smaller local models trade some quality for zero cost.

  • Code edits hot-reload in both containers β€” just save the file.
  • Add a frontend dep: pnpm --dir frontend add <pkg> β†’ docker compose restart frontend
  • Add a backend dep: uv add <pkg> β†’ docker compose up -d --build backend
  • Change .env: docker compose restart <service>
  • Stop: docker compose down (add -v to wipe the DB, Redis & object-storage volumes)

Architecture

NextRole is a supervisor agent orchestrating three specialist subagents on LangGraph + DeepAgents. The main agent handles intake, document processing, and the final battlecard; it delegates research, resume tailoring, and interview coaching to declarative subagents (defined in subagents.yaml, each with its own model, tools, and skills).

NextRole architecture

How It Works

A five-stage pipeline. Stage 4 runs the resume tailor and interview coach in parallel; Stage 6 routes follow-up edits to whichever agent owns the target file.

How NextRole works

  1. Intake β€” the agent asks for your CV, the JD (file, URL, or pasted text), your prep timeline, and any extra context.
  2. Process documents β€” uploads are parsed to markdown via LlamaParse (parse_document); JD URLs are pulled via Tavily (extract_jd). Results land in /processed/, alongside a persisted intake note.
  3. Research β€” the hiring-recon subagent gathers company + role intel and a match analysis β†’ /research/<resume>/<jd>.md.
  4. Tailor & coach (parallel) β€” resume-tailor rewrites the CV as a rendercv YAML and renders a PDF; interview-coach writes a structured prep doc (self-intro + per-round STAR stories).
  5. Battlecard β€” the main agent assembles a one-page-per-round JSON and renders it to a day-of PDF via WeasyPrint.
  6. Multi-turn updates β€” ask for changes in chat; the owning agent reads the existing file, preserves everything you didn't name, and re-renders.

The full procedure (file layout, update routing, source-of-truth conventions) lives in backend/agents/career_agent/README.md. Per-feature design docs are in docs/prd/ β€” an OKF knowledge bundle you can render as an interactive graph; see docs/prd/README.md.

The agent's behavior is configured by files, not hardcoded β€” making it easy to read, diff, and extend:

Primitive Where Role When loaded
Memory CAREER_AGENT.md Per-stage procedure manual (semantic memory) Always (system prompt)
Skills skills/<consumer>/<name>/SKILL.md Task workflows (procedural memory) On demand, per consumer
Subagents subagents.yaml Specialist delegates β†’ the task tool Always
Tools tools.py + DeepAgents built-ins parse_document, extract_jd, render_resume_pdf, render_battlecard_pdf, list_files, overwrite_file, plus read/write/edit_file, ls/glob/grep, execute β€”
Filesystem CompositeBackend Routes virtual paths to the right store (see below) β€”
Middleware middleware.py ModelOverrideMiddleware (runtime LLM swap) + UtcDatetimeMiddleware β€”

Subagents only receive the tools they opt into in YAML β€” tool whitelisting keeps interview-coach, for example, from inheriting the main agent's full toolset.

A single CompositeBackend gives the agent one virtual filesystem while routing each path prefix to the right physical store β€” Postgres for text artifacts, S3-compatible object storage for uploads and rendered PDFs (SeaweedFS locally; S3 / GCS / Azure in the cloud), and a shell backend whose disk holds only render scratch and translates virtual paths to real ones before running commands like rendercv render.

flowchart LR
    Agent["Agent filesystem tools<br/>read_file Β· write_file Β· edit_file<br/>ls Β· glob Β· grep Β· execute"]
    CB{{"CompositeBackend<br/>routes virtual paths"}}
    Agent --> CB
    subgraph Shell["VirtualPathShellBackend Β· default route"]
        SH["shell `execute`<br/>rewrites /virtual/path β†’ on-disk path<br/>(renders run in a throwaway temp dir)"]
    end
    subgraph Store["StoreBackend Β· Postgres + pgvector"]
        ST["/memory/ Β· /processed/ Β· /research/<br/>/interview_coach/<br/>/large_tool_results/ Β· /workspace/"]
    end
    subgraph Obj["ObjectStoreBackend Β· S3-compatible<br/>SeaweedFS local Β· S3/GCS/Azure cloud"]
        OB["/upload/ Β· /tailored_resume/<br/>/interview_battlecard/"]
    end
    CB -->|default: shell + scratch| Shell
    CB -->|KV routes| Store
    CB -->|artifact routes| Obj
    Sem["Semantic memory Β· CAREER_AGENT.md"] -. loaded into system prompt .-> Agent
    Proc["Procedural memory Β· skills/*/SKILL.md"] -. loaded on demand .-> Agent
    Work["Working memory Β· LangGraph thread"] -. drives .-> Agent
    Store --- Epi["Episodic memory Β· persisted artifacts<br/>(incl. /memory/ auto-memory)"]
    Obj --- Epi

Mapped to memory types:

  • Working memory β€” the live LangGraph conversation thread.
  • Semantic memory β€” CAREER_AGENT.md, always in the system prompt.
  • Procedural memory β€” skills/*/SKILL.md, loaded on demand.
  • Episodic memory β€” persisted artifacts in Postgres + disk, including auto-memory: standing preferences saved to the /memory/ route and auto-applied across sessions.

NextRole runs zero-login single-user by default β€” docker compose up and start prepping, no accounts. Flip on multi-user mode for a shared or cloud deployment and every user gets private threads, files, and memory.

  • Login β€” Google OAuth and/or email + password, via self-hosted Better Auth inside the Next.js app (its tables live in your Postgres; no third-party auth vendor).
  • Isolation β€” the agent server verifies a short-lived JWT (JWKS) on every request; threads/runs/crons are owner-scoped in SQL (unowned β†’ 404), and store namespaces + object keys are scoped per user (users/<id>/…). Design details in backend/ARCHITECTURE.md Β§8.

Enable it β€” set these in .env, then docker compose up -d frontend backend:

  1. AUTH_ENABLED=true and BETTER_AUTH_SECRET=$(openssl rand -base64 32).
  2. Create the Better Auth tables once (it owns user / session / account / jwks, separate from backend/storage/migrations/):
    AUTH_DATABASE_URL="postgresql://<POSTGRES_USER>:<POSTGRES_PASSWORD>@localhost:<POSTGRES_LOCAL_PORT>/<POSTGRES_DB>" \
    BETTER_AUTH_SECRET=<same secret> \
      pnpm --dir frontend dlx @better-auth/cli@latest migrate --config src/lib/auth/server.ts
    
  3. LANGGRAPH_AUTH={"path": "/deps/next-role/backend/agents/auth.py:auth", "disable_studio_auth": true} β€” turns on backend enforcement. (Login without this is fine for trying the UI, but provides no isolation.)
  4. Optional Google sign-in: AUTH_GOOGLE_ENABLED=true + GOOGLE_AUTH_CLIENT_ID / GOOGLE_AUTH_CLIENT_SECRET (OAuth client redirect URI http://localhost:<FRONTEND_LOCAL_PORT>/api/auth/callback/google). Email + password works without it.
  • REQUIRE_AUTH=true β€” the backend refuses to boot if LANGGRAPH_AUTH is missing, so a misconfigured deploy fails loudly instead of serving everyone's data.
  • HTTPS everywhere β€” set BETTER_AUTH_URL / AUTH_JWT_ISSUER / AUTH_JWT_AUDIENCE to the public https origin, and AUTH_JWKS_URL to the in-network frontend URL the backend can reach.
  • Pin CORS β€” CORS_ALLOW_ORIGINS=https://your-frontend.example (the default * is local-only).
  • Block the unauthenticated meta routes at the ingress β€” /metrics leaks thread/run counts; also /docs, /openapi.json, /info.
  • Gate MCP / A2A β€” authentication-only today (no per-resource authz), so disable via LANGGRAPH_HTTP "disable_mcp": true / "disable_a2a": true until audited.
  • Close the Studio backdoors β€” never set LANGSMITH_LANGGRAPH_API_VARIANT=local_dev in production; disable_studio_auth: true (above) closes the header-based one.
  • Reverse proxy must never forward a client-controlled root_path (the in-process /noauth loopback bypass stays internal-only).
Layer Stack
Backend Python 3.13 Β· LangChain v1 Β· LangGraph 1.x Β· DeepAgents 0.6 Β· uv Β· served by NextRole's own self-hosted agent server (backend/ARCHITECTURE.md)
Agent I/O Tavily (web search) Β· LlamaParse / LlamaCloud (document parsing) Β· rendercv (resume β†’ PDF) Β· WeasyPrint (battlecard β†’ PDF)
Frontend Next.js 16 Β· React 19 Β· TypeScript Β· Tailwind Β· pnpm Β· @langchain/react (v2 useStream)
Data PostgreSQL 18 + pgvector Β· Redis 8 Β· S3-compatible object storage (SeaweedFS locally; S3 / GCS / Azure in the cloud)
Infra Docker Compose (frontend Β· backend Β· core-server Β· postgres Β· redis Β· object-store)
Observability LangSmith

Because NextRole ships its own agent server implementing the LangGraph Server API (see backend/ARCHITECTURE.md), the career_agent assistant is also reachable by other tools and agents β€” no extra code:

  • MCP β€” exposed as Model Context Protocol tools at /mcp (Streamable HTTP), usable by any MCP-compliant client. β†’ docs
  • A2A β€” Google's Agent2Agent protocol at /a2a/{assistant_id} (JSON-RPC 2.0; message/send + message/stream). β†’ docs
  • The full server API is browsable at the /docs endpoint of your deployment.

In multi-user mode these endpoints are authentication-gated but not yet per-user authorized β€” disable them (disable_mcp / disable_a2a) in a shared deployment until that lands. See backend/ARCHITECTURE.md Β§8.

NextRole Agent Expose

Set LANGCHAIN_API_KEY and LANGCHAIN_TRACING_V2=true in .env, and every run β€” each LLM call, tool call, and nested subagent β€” is traced at smith.langchain.com under the LANGCHAIN_PROJECT you configure. Optional, but invaluable for debugging the multi-agent flow.

Roadmap

  • πŸ’€ "Auto-dream" consolidation β€” sleep-time compaction that prunes stale notes and merges insights into durable memory.
  • πŸ“¦ Remote sandboxes β€” swap LocalShellBackend for an isolated remote sandbox (e.g. Daytona) so render/shell steps are safe for multi-tenant use.
  • πŸ“Š Agent evaluation β€” LangSmith evals over the workflow (the @pytest.mark.eval marker is already reserved).
  • 🎨 Enhanced UI β€” richer artifact editing, diff views, and inline regeneration.
  • πŸ”Œ MCP / A2A examples β€” sample integrations driving career_agent from external agents and IDEs.
  • ☁️ Cloud deployment β€” binary artifacts already live in S3-compatible object storage (SeaweedFS locally; point OBJECT_STORE_* at S3 / GCS / Azure). Remaining: managed bucket provisioning (versioning, SSE, IAM) and presigned-URL delivery.
  • 🌐 More sources & ATS-aware tailoring β€” pluggable retrievers + keyword/ATS optimization passes.

Limitations

Multi-user mode isolates data, but the shell sandbox below is still the gate before opening signups to untrusted users.

  • πŸ”’ Local shell execution β€” VirtualPathShellBackend runs render commands via subprocess on the host. Safe locally and for a trusted team; not hardened for untrusted multi-tenant use (needs sandboxing β€” see roadmap). Isolate render/shell steps before exposing public signup.
  • πŸ§ͺ LLM evals deferred β€” current tests are unit + local-DB integration; automated quality evals aren't wired up yet.
  • 🧠 Personalization is preferences-only β€” the agent persists and auto-applies the preferences you state across sessions, but doesn't yet infer your style/history on its own or consolidate memory over time (see roadmap).
  • ⏱️ Latency β€” a full run makes several LLM and tool calls across multiple agents; expect minutes, not seconds.

πŸ—ΊοΈ Explore the codebase graph

This repo ships a pre-built architecture knowledge graph in .ua/ β€” the whole codebase mapped by Understand-Anything into 1,100+ nodes across 10 architectural layers, with a guided tour. Browse it as an interactive dashboard:

# From the repo root β€” needs only Node.js (no install, no clone, no build):
npx --yes "https://github.com/Egonex-AI/Understand-Anything/releases/latest/download/understand-anything-viewer.tgz" .

Open the printed πŸ”‘ Dashboard URL (include the ?token=… β€” the plain URL hits an access gate).

Using Claude Code? Install the understand-anything plugin and run /understand-dashboard in this repo instead.

The graph is for humans: AI coding assistants are configured to ignore .ua/ (Claude Code deny rules, .cursorignore, a CLAUDE.md instruction) so they keep reading the real source instead of a large generated snapshot.

NextRole codebase knowledge graph β€” architectural layers, dependencies, and project stats in the Understand-Anything dashboard

The same treatment exists for the product's design history: every feature ships with a PRD in docs/prd/ β€” an OKF knowledge bundle whose committed interactive graph (docs/prd/viz.html) maps how features extend and supersede each other. The codebase graph maps the code; the PRD graph maps the decisions. See docs/prd/README.md to browse or regenerate it.

Contributing

PRs and issues are welcome! Start with CONTRIBUTING.md β€” it walks through the fork β†’ PR workflow, local setup, the CI quality gate (code quality + backend tests + frontend tests), testing, and conventions. Stack-specific details live in backend/CLAUDE.md and frontend/CLAUDE.md; commits follow Conventional Commits.

New here? Issues labelled good first issue are a gentle place to start, and questions are welcome in Discussions.

License

MIT Β© 2026 Tam Nguyen

Acknowledgements

Built on DeepAgents, LangChain / LangGraph / LangSmith, rendercv, WeasyPrint, Tavily, and LlamaIndex / LlamaParse.