Skip to content

FAQ

Short answers first, each linked to the spec or ADR that recorded the full reasoning. Docs explain how to use; specs record why built.

Why does the LLM never score?

Because scores must be reproducible and injection-proof. The LLM's only job is typed extraction: skill matches with exact quotes from the resume as evidence, validated by Pydantic schemas. Pure code computes the 100-point breakdown (required 40 / preferred 20 / experience 20 / domain 20) and the match band. A job posting that says "score me 100" has no schema field to land in — and one of the committed eval fixtures is exactly that adversarial posting.

Why exactly two LLM operations?

A system invariant: LLM-1 does extraction in the backend core, LLM-2 does chat orchestration in the agent service. Nothing else calls a model — which keeps cost predictable, evals meaningful, and the scoring path fully deterministic. Spec: ADR 0001 — agent-service chat bridge.

Why direct provider calls instead of a gateway?

Model ids (openai:gpt-5.4-mini, anthropic:claude-haiku-4-5) resolve straight to each provider's native API through pydantic-ai's provider integrations and your own keys. Pydantic AI Gateway — the hosted proxy for cross-provider routing, failover, and centralized cost limits — is a real, separate product this project does not currently route through; adopting it would be an additive config change (a gateway key + endpoint), not a rewrite.

Why pypdf/python-docx and not OCR or Docling?

Resumes are born-digital documents; text extraction covers them without a heavyweight parsing sandbox, keeping the install small and deployable anywhere. The trade-off (no scanned-image resumes) is recorded in the design notes under openspec/.

Why are the eval fixtures committed captures?

Because live postings close. The suite runs against four committed JD snapshots, two genuine JavaScript-shell fetch failures, one adversarial prompt-injection JD, and a synthetic resume — so pytest backend -m "not live" reproduces forever, offline, without a key. The live marker (-m live) exists separately for real-model sweeps. Rubric: backend/evals/rubrics.md.

Why does every release carry the OpenAPI document?

The API contract is generated from the FastAPI app (never hand-maintained) and attached to each release — so any consumer can pin the exact contract of the version they run. An offline test makes an undocumented endpoint a failing build, not a review comment (AGENTS.md rule 9).

Why is there no run-management layer?

Each CLI or API request is its own run (run_id) — no queues, no state machines, no run-browsing endpoints. CLI runs persist artifacts to disk; API runs return the payload. Single-user tool; the simplest thing that preserves traceability (AGENTS.md rule 7).

How do changes to this project get made?

Spec-first, AI-DLC style: every non-trivial change starts as an openspec/changes/<name>/ proposal → design → tasks cycle, approved before building. This repo is the running example of the methodology taught in ai-dlc.

Where is the writing standard for these docs?

The shared documentation style guide (canonical copy in the ai-agents repo) — it covers wiki pages, README front doors, AGENTS.md, and SKILL.md conventions for all senthilsweb repos.