Imported from yuryfomichov/the_interviewee (
AGENTS.md). Install upstream withnpx skills add yuryfomichov/the_interviewee. Copyright stays with the author.
Project Agent Playbook
Mission
- Safeguard the retrieval-assisted interview assistant: preserve existing workflows, ensure conversations stay logged, and keep responses grounded in user career data.
- Before coding, confirm intended behaviour, required inputs, and tests with the requester; surface blockers (missing config, sandbox limits) early.
Architecture Map
src/app.py→ Entry point; initializes config, creates RAG engine via factory, and launches UI.src/launchers/→ UI abstraction layer (Gradio or CLI) selected viaLAUNCHER_TYPEenv var.factory.py→ Creates launcher instances based on configuration.gradio_launcher.py→ Web interface implementation.cli_launcher.py→ Terminal interface implementation.
src/rag_engine/engine.py→ Orchestrates retrieval, prompt formatting, history, and logging.src/rag_engine/prompt_logger.py→ Persists question/prompt/answer tuples to timestamped logs.src/llm/factory.py→ Chooses an LLM backend (MLX Qwen/Llama or OpenAI) based onConfig.model_provider.src/llm/mlx_llm.py/src/llm/openai_llm.py→ Concrete implementations; both expect a LangChain retriever and must setlast_promptfor logging.src/document_loader/→ Document loading and vector store management.huggingface_loader.py→ Builds/loads Chroma vector store fromcareer_data/.factory.py→ Creates document loader instances (currently only HuggingFace).
Core Guidelines
- Reuse the singleton: obtain configuration via
get_config(); avoid constructing freshConfigobjects outside tests so settings (model, paths, tokens) stay in sync across components. - Keep provider enums aligned: the provider keys
{"qwen", "llama", "openai"}must matchconfig.yaml, environment variables (viaMODEL_PROVIDER), andPROVIDER_CONFIGinsrc/llm/factory.py. Default provider is"qwen"if not specified. Update all touchpoints plus docs/tests together when introducing a new provider. - Preserve prompt plumbing:
RAGEngine.generate_response()expectsLLMInterface.invoke()/.stream()to return strings, respect streaming, and updateself.last_prompt. Do not removePromptLoggerwrites or manual history management. - Handle mixed retriever outputs: Retrieval can yield LangChain
Documentobjects or plain strings. Any context formatting logic must treat both (seesrc/llm/openai_llm.py:_format_docsandsrc/llm/mlx_llm.py:_format_docs). - Respect logging contract: Use
logging.getLogger(__name__)and never introduceprint()in library code. Initialisation routines should log model names, devices, and recoverable failures. - Keep text encoding consistent: project tooling assumes ASCII for most files; UTF-8 is used only where essential (prompt logs in
prompts/, career data incareer_data/).
Coding Standards
- Format with
ruff format src/ tests/and lint viaruff check src/ tests/; line length is 100, strings default to double quotes (pyproject.toml). - Maintain type hints on all functions; prefer
collections.abctypes for annotations. - Organize imports standard-lib → third-party → local; remove unused imports.
- Add comments sparingly—only when intent is non-obvious.
- For configuration additions, modify
src/config.py,config.yaml,.env.example, and documentation together.
Testing & Validation
- Baseline checks:
pytest -v,ruff check, and targeted component tests for new logic. Add unit tests when behaviour changes or bugs are fixed. - Current test debt:
tests/test_config.pystill assertsmodel_provider in ["local", "openai"]but actual valid providers are{"qwen", "llama", "openai"}. This test needs updating. - For MLX-dependent code, consider guard tests or feature flags so CI without Apple Silicon can still pass (mock imports when necessary).
- Test coverage reports are generated in
htmlcov/viapytest --cov=src --cov-report=html.
Workflow Tips
- When adding LLM backends:
- Implement a class inheriting
LLMInterfaceinsrc/llm/. - Extend
PROVIDER_CONFIGinsrc/llm/factory.pywith backend type and system prompt hook. - Register configuration defaults in
config.yamlundermodel.<provider>section. - Update
Config._load_model_settingsinsrc/config.pyto load the new provider settings. - Supply retrieval-aware prompts that set
self.last_promptfor logging. - Update tests, documentation, and
.env.exampleto reflect the new provider.
- Implement a class inheriting
- When adding launcher types:
- Implement a class inheriting
BaseLauncherinsrc/launchers/. - Register in
create_launcherfactory function. - Update
LAUNCHER_TYPEdocumentation in.env.example.
- Implement a class inheriting
- When tweaking RAG heuristics, keep
_is_out_of_scopebehaviour configurable if thresholds/keywords expand. - To introduce new persistence (e.g., analytics), mirror
PromptLoggerpatterns: lazy directory creation, UTF-8 writes, error suppression via logging. - For vector store changes, ensure CLI entry points work: run
python -m src.document_loader.huggingface_loaderor use the VSCode task "Rebuild Vector Database".
Data & Secrets
.envcarriesMODEL_PROVIDER(values:qwen,llama,openai),LAUNCHER_TYPE(values:gradio,cli),USER_NAME, and API tokens; never hardcode secrets..env,career_data/,prompts/,vector_db/, andmodels/are gitignored—do not remove protections.- Respect
vector_db/andmodels/as generated/cached content; rebuild vector DB when data schema changes. - Career documents in
career_data/*.mdcontain private information—never commit or expose publicly.
Common Pitfalls
- Attempting to instantiate MLX models on non-Apple Silicon: guard with
IS_APPLE_SILICONand raise helpful errors (keep guidance to installmlx/mlx-lm). - Forgetting to update
PromptLogger.logcall sites after signature changes results in empty prompt history files. - Breaking streaming:
RAGEngineyields tokens; ensure new LLM backends stream iterables of strings and close generators cleanly. - Neglecting doc updates (
README.md,.claudeguides) when behaviour visibly changes—users rely on those for setup.
Tooling Notes
- Run inside the project virtual environment (
uv venv+source .venv/bin/activate); assume dependencies and CLI tasks execute from that shell. - Start the app with
uv run python -m src.app; the launcher (Gradio or CLI) is selected viaLAUNCHER_TYPEin.env(gradioby default, set toclifor terminal mode). - Package manager:
uv; preferuv pipfor dependency installs. - Type checking:
pyright(configured viapyrightconfig.json) ormypyif needed. - Coverage reports live in
htmlcov/; regenerate withpytest --cov=src --cov-report=html.
Keep this playbook nearby; update it whenever the development workflow, supported providers, or critical constraints change.
