|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +readmycareer.com is an AI career-coaching PoC built as a **pnpm monorepo**. A Next.js 14 (App Router) frontend talks to API routes that drive a multi-agent pipeline (Google ADK + Gemini 3.1 Flash Lite Preview). Agents call MCP stdio subprocesses for skill isolation, and use Pinecone RAG plus Supabase (Postgres + Auth + RLS) for persistence. |
| 8 | + |
| 9 | +Pipeline: `pdf-word-to-json` (MCP) → `GapAnalyzerAgent` → `PlannerAgent` → (after todos done) `ResumeOptimizerAgent`. A separate stateful `ChatQnAAgent` powers the in-app coach. Each step runs inside a **quality gate loop** (≤ 2–3 retries) that validates Zod schemas, plan completeness (≥ 3 todos/week), and date continuity before accepting a result. |
| 10 | + |
| 11 | +See [README.md](./README.md) and [AGENTS.md](./AGENTS.md) for canonical architecture diagrams. Per-subsystem context lives in `.gemini/skills/<name>/SKILL.md` (Gemini CLI workspace skills) — read the matching skill file before editing an agent or MCP skill. |
| 12 | + |
| 13 | +## Repository Context |
| 14 | + |
| 15 | +This is a **pnpm workspace** monorepo (`pnpm-workspace.yaml`). Only `agents/` and `mcp-skills/*` are runtime packages alongside `app/`; everything else is tooling or docs. |
| 16 | + |
| 17 | +``` |
| 18 | +readmycareer.com/ |
| 19 | +├── app/ Next.js 14 App Router frontend + API routes |
| 20 | +│ └── src/app/ |
| 21 | +│ ├── (@chat|@goal|@plan|@upload)/ parallel route slots |
| 22 | +│ ├── api/ DB + agent entry points (SSE-capable) |
| 23 | +│ ├── dashboard/ authenticated user plans |
| 24 | +│ ├── admin/ admin-only observability view |
| 25 | +│ └── share/ public read-only plan view |
| 26 | +├── agents/ Google ADK agents (orchestrator + 4 agents) — runtime |
| 27 | +│ ├── orchestrator.ts public API: runCareerAnalysis / runChatQnA / runResumeOptimizer |
| 28 | +│ ├── types.ts single source of truth for all agent I/O Zod schemas |
| 29 | +│ └── lib/ |
| 30 | +│ ├── mcp-client.ts connection-pooled MCP stdio client |
| 31 | +│ ├── models.ts model ids + pricing registry (reads config/model-pricing.json) |
| 32 | +│ ├── model-adapter.ts provider-agnostic LLM adapter; adapters/ = gemini + openai |
| 33 | +│ └── observability.ts per-stage telemetry + in-process aggregate |
| 34 | +├── mcp-skills/ MCP stdio subprocesses spawned by agents — runtime |
| 35 | +│ ├── pdf-word-to-json/ resume extraction |
| 36 | +│ ├── career-knowledge-base/ Pinecone RAG |
| 37 | +│ ├── career-plan-generator/ structured plan JSON |
| 38 | +│ └── resume-generator/ ATS resume synthesis |
| 39 | +├── eval/ ragas + agent harness (Python) — ship gate |
| 40 | +├── supabase/ SQL migrations + RLS policies |
| 41 | +├── config/ shared cross-language config (model-pricing.json) |
| 42 | +├── documents/ product/design docs + generated eval report |
| 43 | +└── .gemini/skills/ per-subsystem SKILL.md (progressive disclosure) |
| 44 | +``` |
| 45 | + |
| 46 | +**Rules for working in this repo:** |
| 47 | + |
| 48 | +- **Respect workspace boundaries.** Cross-package imports go through the published workspace name (`@readmycareer/agents`), never via relative `../../agents/...` paths from `app/`. |
| 49 | +- **Read the matching `.gemini/skills/<name>/SKILL.md` first** before editing `agents/<name>/index.ts` or `mcp-skills/<name>/src/index.ts`. The global `AGENTS.md` stays lightweight by design — detailed I/O specs live in the skills. |
| 50 | +- **Schema migrations** belong in `supabase/` and must include RLS policies. Never modify a published migration; add a new one. |
| 51 | +- **Generated artifacts (`dist/`, `.next/`, `node_modules/`) are gitignored.** Do not commit them, and do not edit files under them. |
| 52 | +- **Secrets live in `app/.env.local`** (`GOOGLE_API_KEY`, `PINECONE_*`, `NEXT_PUBLIC_SUPABASE_*`). The `readmycareer-*.json` service-account file at the root is a secret — never log, paste, or commit it. |
| 53 | +- **Docs that drive behavior**: [README.md](./README.md), [AGENTS.md](./AGENTS.md), [DESIGN.md](./DESIGN.md), [CHANGELOG.md](./CHANGELOG.md). Update [CHANGELOG.md](./CHANGELOG.md) when shipping a user-visible change. |
| 54 | + |
| 55 | +## Architecture Boundaries — Hard Rules |
| 56 | + |
| 57 | +These boundaries exist so the agent layer remains a pure function of its inputs (the eval harness depends on it): |
| 58 | + |
| 59 | +- **Agents do not touch Supabase, Pinecone, or the filesystem directly.** All external access goes through `callMcpTool()` in [agents/lib/mcp-client.ts](agents/lib/mcp-client.ts), or is performed in the API route layer. |
| 60 | +- **DB I/O lives in API routes** under [app/src/app/api/](app/src/app/api/) — fetching agent inputs and persisting results (`career_plans`, `gap_analyses`, `roadmaps`, `optimized_resumes`, chat history). |
| 61 | +- **MCP skills are spawned via the connection-pooled client** in [agents/lib/mcp-client.ts](agents/lib/mcp-client.ts). Never `spawn()` an MCP subprocess elsewhere. |
| 62 | +- **All agent I/O types live in [agents/types.ts](agents/types.ts)** and are validated with Zod at every boundary. |
| 63 | +- **Public agent surface** is `runCareerAnalysis`, `runChatQnA`, `runResumeOptimizer` from [agents/orchestrator.ts](agents/orchestrator.ts). App code must not import individual agents. |
| 64 | +- **LLM calls go through the `ModelAdapter` interface** ([agents/lib/model-adapter.ts](agents/lib/model-adapter.ts)) — never construct a provider SDK client in an agent or the orchestrator. The gap-analysis stage is provider-swappable (`provider` arg / `MODEL_PROVIDER` env). |
| 65 | +- **Observability stays boundary-safe**: the orchestrator emits per-stage metrics via the `onMetric` callback; the API route persists them to `agent_runs`. Agents never log to or touch the DB. |
| 66 | + |
| 67 | +## Gemini / Agent Guidelines |
| 68 | + |
| 69 | +- **Model**: `gemini-3.1-flash-lite-preview` for all agents and MCP skills. Do not silently switch models, and never hardcode a model string — model ids + pricing live in one registry, [agents/lib/models.ts](agents/lib/models.ts) (`GEMINI_MODEL` / `OPENAI_MODEL`; prices from `config/model-pricing.json`). App imports it via `@readmycareer/agents/models`; MCP skills (separate processes) read the same `GEMINI_MODEL` env var, so setting it once switches everything. |
| 70 | +- **Framework**: Google ADK TypeScript (`@google/adk`) with `InMemorySessionService`. |
| 71 | +- **Caching**: resume tokens use Gemini Context Caching (1h TTL) — preserve cache keys when refactoring. |
| 72 | +- **Bilingual output**: all agent output respects `Accept-Language` (en / ko). Never hardcode the response language. |
| 73 | +- **Quality gates**: any new agent must be wrapped in a retry loop that validates schema + domain rules before returning. Mirror the pattern already in `gap-analyzer` / `planner`. |
| 74 | + |
| 75 | +## Eval Discipline |
| 76 | + |
| 77 | +The eval suite ([eval/run_evals.sh](eval/run_evals.sh)) is the contract for shipping changes that touch agents, MCP skills, prompts, or RAG: |
| 78 | + |
| 79 | +- **Run `pnpm eval` before declaring agent/MCP/RAG work complete.** A failing eval blocks the change — do **not** weaken thresholds in `agent_harness.py` / `ragas_eval.py` to make it pass. |
| 80 | +- The agent harness requires `pnpm dev` to be running on `BASE_URL` (default `http://localhost:3000`). |
| 81 | +- Tracked metrics: Schema Compliance, Gap Faithfulness, **Gap Recall/Precision vs. labels**, Plan Completeness, Date Consistency, **Hidden Expectation Coverage**, **Contextual Depth**, p95 Latency, Avg Cost (agents); Faithfulness, Answer Relevancy, Context Precision/Recall, **Grounding/Citation Rate** (RAG). The harness also supports `--repeat N` (variance) and `--save-baseline`/`--compare-baseline` (regression diff). |
| 82 | +- Inspect `eval/agent_harness_results.csv`, `eval/ragas_results.csv`, and `eval/grounding_results.csv` — review the CSV, not just the PASS/FAIL summary. Each agent run also regenerates a human-readable Korean report at [documents/agent-eval-report.md](documents/agent-eval-report.md). |
| 83 | +- To extend coverage, add cases to [eval/eval_dataset.json](eval/eval_dataset.json) and `eval/fixtures/` rather than relaxing assertions. |
| 84 | + |
| 85 | +## Frontend Guidelines |
| 86 | + |
| 87 | +- **Next.js 14 App Router** — default to **Server Components**; mark Client Components with `"use client"` only when interactivity, hooks, or browser APIs require it. |
| 88 | +- **Hybrid rendering / Streaming SSR**: |
| 89 | + - Prefetch on the server with `QueryClient.prefetchQuery` and pass through `<HydrationBoundary state={dehydrate(qc)}>` so the client takes over with a warm cache. |
| 90 | + - Use `loading.tsx` and `<Suspense>` boundaries to stream above-the-fold UI first; never block a route on a slow agent call. |
| 91 | + - For long-running agent runs, stream via Server-Sent Events from `app/src/app/api/` and render incremental progress. |
| 92 | +- **TanStack Query (`@tanstack/react-query`)** is the single source of truth for server state on the client. Centralize keys in the shared `queryKeys` module; co-locate query/mutation hooks (`useResumeQuery`, `useCareerPlans`, `useChatMessages`, …) and do not duplicate fetching logic in components. |
| 93 | +- **Styling: shadcn/ui + Tailwind CSS only.** No CSS modules, no styled-components, no inline `style` for design concerns. |
| 94 | + - Read [DESIGN.md](./DESIGN.md) before any UI work — the Synthetic Intelligence design system is mandatory. |
| 95 | + - Never use raw Tailwind palette colors (e.g. `bg-blue-600`, `bg-gray-100`) — use design tokens. |
| 96 | + - Use `cn()` (clsx + tailwind-merge) for conditional class composition. |
| 97 | +- **i18n**: all user-facing strings go through `next-intl` keys in both `en.json` and `ko.json`. Never hardcode strings in JSX. |
| 98 | +- **Code quality**: keep components small and presentational where possible, with explicit prop types. Prefer composition over flag props. Do not introduce abstractions that aren't justified by an existing second caller. |
| 99 | + |
| 100 | +## Commit Workflow |
| 101 | + |
| 102 | +When the user says **"커밋해"**, immediately (no confirmation prompt) split the working tree into logically scoped commits and create them. All commit messages must be **English** and follow Conventional Commits: |
| 103 | + |
| 104 | +``` |
| 105 | +<type>(<scope>): <subject ≤ 50 chars, imperative, no trailing period> |
| 106 | +
|
| 107 | +- bullet 1 (what & why, not how) |
| 108 | +- bullet 2 |
| 109 | +
|
| 110 | +Resolves: #<issue> ← omit entirely if no issue number is associated |
| 111 | +``` |
| 112 | + |
| 113 | +Common types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`, `perf`, `build`, `ci`. Typical scopes for this repo: `agents`, `gap-analyzer`, `planner`, `chat`, `resume-optimizer`, `mcp`, `rag`, `api`, `dashboard`, `auth`, `i18n`, `eval`, `ui`. |
0 commit comments