vacancy-radar 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vacancy_radar-0.1.0/.gitignore +12 -0
- vacancy_radar-0.1.0/CHANGELOG.md +66 -0
- vacancy_radar-0.1.0/LICENSE +21 -0
- vacancy_radar-0.1.0/PKG-INFO +449 -0
- vacancy_radar-0.1.0/README.md +418 -0
- vacancy_radar-0.1.0/docs/evaluation.md +112 -0
- vacancy_radar-0.1.0/docs/import-guide.md +196 -0
- vacancy_radar-0.1.0/docs/releasing.md +177 -0
- vacancy_radar-0.1.0/eval/__init__.py +10 -0
- vacancy_radar-0.1.0/eval/metrics.py +43 -0
- vacancy_radar-0.1.0/eval/queries.yaml +321 -0
- vacancy_radar-0.1.0/eval/run.py +267 -0
- vacancy_radar-0.1.0/pyproject.toml +108 -0
- vacancy_radar-0.1.0/src/vacancy_radar/__init__.py +8 -0
- vacancy_radar-0.1.0/src/vacancy_radar/cli.py +800 -0
- vacancy_radar-0.1.0/src/vacancy_radar/config.py +227 -0
- vacancy_radar-0.1.0/src/vacancy_radar/core.py +1258 -0
- vacancy_radar-0.1.0/src/vacancy_radar/frontmatter.py +86 -0
- vacancy_radar-0.1.0/src/vacancy_radar/ids.py +47 -0
- vacancy_radar-0.1.0/src/vacancy_radar/index/__init__.py +6 -0
- vacancy_radar-0.1.0/src/vacancy_radar/index/build.py +425 -0
- vacancy_radar-0.1.0/src/vacancy_radar/index/embed.py +38 -0
- vacancy_radar-0.1.0/src/vacancy_radar/index/extract.py +148 -0
- vacancy_radar-0.1.0/src/vacancy_radar/index/schema.py +76 -0
- vacancy_radar-0.1.0/src/vacancy_radar/index/search.py +429 -0
- vacancy_radar-0.1.0/src/vacancy_radar/index/snippet.py +50 -0
- vacancy_radar-0.1.0/src/vacancy_radar/index/store.py +53 -0
- vacancy_radar-0.1.0/src/vacancy_radar/mcp_server.py +609 -0
- vacancy_radar-0.1.0/src/vacancy_radar/models.py +201 -0
- vacancy_radar-0.1.0/src/vacancy_radar/vault/__init__.py +5 -0
- vacancy_radar-0.1.0/src/vacancy_radar/vault/hashing.py +20 -0
- vacancy_radar-0.1.0/src/vacancy_radar/vault/paths.py +120 -0
- vacancy_radar-0.1.0/src/vacancy_radar/vault/reader.py +394 -0
- vacancy_radar-0.1.0/tests/conftest.py +18 -0
- vacancy_radar-0.1.0/tests/eval/test_findings.py +83 -0
- vacancy_radar-0.1.0/tests/eval/test_metrics.py +71 -0
- vacancy_radar-0.1.0/tests/eval/test_queries.py +159 -0
- vacancy_radar-0.1.0/tests/eval/test_run.py +141 -0
- vacancy_radar-0.1.0/tests/fixtures/generate.py +748 -0
- vacancy_radar-0.1.0/tests/fixtures/pdfs.py +95 -0
- vacancy_radar-0.1.0/tests/fixtures/test_generate.py +400 -0
- vacancy_radar-0.1.0/tests/fixtures/test_pdfs.py +55 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/.vacancy-radar/.gitkeep +0 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2022-03-22-acme-corp-backend-engineer/documents/2022-03-22-acme-corp-backend-engineer-doc1.pdf +1 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2022-03-22-acme-corp-backend-engineer/documents/2022-03-22-acme-corp-backend-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2022-03-22-acme-corp-backend-engineer/documents/2022-03-22-acme-corp-backend-engineer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2022-03-22-acme-corp-backend-engineer/documents/2022-03-22-acme-corp-backend-engineer-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2022-03-22-acme-corp-backend-engineer/documents/2022-03-22-acme-corp-backend-engineer-doc5.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2022-03-22-acme-corp-backend-engineer/documents/2022-03-22-acme-corp-backend-engineer-doc6.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2022-03-22-acme-corp-backend-engineer/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2024-12-14-acme-corp-frontend-developer/documents/2024-12-14-acme-corp-frontend-developer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2024-12-14-acme-corp-frontend-developer/documents/2024-12-14-acme-corp-frontend-developer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2024-12-14-acme-corp-frontend-developer/documents/2024-12-14-acme-corp-frontend-developer-doc3.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2024-12-14-acme-corp-frontend-developer/documents/2024-12-14-acme-corp-frontend-developer-doc4.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/2024-12-14-acme-corp-frontend-developer/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/acme-corp/_company.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2022-06-14-blueprint-works-backend-engineer/documents/2022-06-14-blueprint-works-backend-engineer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2022-06-14-blueprint-works-backend-engineer/documents/2022-06-14-blueprint-works-backend-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2022-06-14-blueprint-works-backend-engineer/documents/2022-06-14-blueprint-works-backend-engineer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2022-06-14-blueprint-works-backend-engineer/documents/2022-06-14-blueprint-works-backend-engineer-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2022-06-14-blueprint-works-backend-engineer/documents/2022-06-14-blueprint-works-backend-engineer-doc5.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2022-06-14-blueprint-works-backend-engineer/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2024-06-19-blueprint-works-qa-engineer/documents/2024-06-19-blueprint-works-qa-engineer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2024-06-19-blueprint-works-qa-engineer/documents/2024-06-19-blueprint-works-qa-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2024-06-19-blueprint-works-qa-engineer/documents/2024-06-19-blueprint-works-qa-engineer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/2024-06-19-blueprint-works-qa-engineer/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/blueprint-works/_company.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-04-26-dummy-data-co-data-analyst/documents/2022-04-26-dummy-data-co-data-analyst-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-04-26-dummy-data-co-data-analyst/documents/2022-04-26-dummy-data-co-data-analyst-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-04-26-dummy-data-co-data-analyst/documents/2022-04-26-dummy-data-co-data-analyst-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-04-26-dummy-data-co-data-analyst/documents/2022-04-26-dummy-data-co-data-analyst-doc4.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-04-26-dummy-data-co-data-analyst/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-06-18-dummy-data-co-technical-writer/documents/2022-06-18-dummy-data-co-technical-writer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-06-18-dummy-data-co-technical-writer/documents/2022-06-18-dummy-data-co-technical-writer-doc2.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-06-18-dummy-data-co-technical-writer/documents/2022-06-18-dummy-data-co-technical-writer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-06-18-dummy-data-co-technical-writer/documents/2022-06-18-dummy-data-co-technical-writer-doc4.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-06-18-dummy-data-co-technical-writer/documents/2022-06-18-dummy-data-co-technical-writer-doc5.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2022-06-18-dummy-data-co-technical-writer/vacancy.md +13 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2024-07-12-dummy-data-co-backend-engineer/documents/2024-07-12-dummy-data-co-backend-engineer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2024-07-12-dummy-data-co-backend-engineer/documents/2024-07-12-dummy-data-co-backend-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2024-07-12-dummy-data-co-backend-engineer/documents/2024-07-12-dummy-data-co-backend-engineer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2024-07-12-dummy-data-co-backend-engineer/documents/2024-07-12-dummy-data-co-backend-engineer-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2024-07-12-dummy-data-co-backend-engineer/documents/2024-07-12-dummy-data-co-backend-engineer-doc5.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/2024-07-12-dummy-data-co-backend-engineer/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/dummy-data-co/_company.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2022-06-09-example-systems-product-designer/documents/2022-06-09-example-systems-product-designer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2022-06-09-example-systems-product-designer/documents/2022-06-09-example-systems-product-designer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2022-06-09-example-systems-product-designer/documents/2022-06-09-example-systems-product-designer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2022-06-09-example-systems-product-designer/documents/2022-06-09-example-systems-product-designer-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2022-06-09-example-systems-product-designer/documents/2022-06-09-example-systems-product-designer-doc5.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2022-06-09-example-systems-product-designer/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2023-10-24-example-systems-backend-engineer/documents/2023-10-24-example-systems-backend-engineer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2023-10-24-example-systems-backend-engineer/documents/2023-10-24-example-systems-backend-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2023-10-24-example-systems-backend-engineer/documents/2023-10-24-example-systems-backend-engineer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2023-10-24-example-systems-backend-engineer/documents/2023-10-24-example-systems-backend-engineer-doc4.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2023-10-24-example-systems-backend-engineer/documents/2023-10-24-example-systems-backend-engineer-doc5.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/2023-10-24-example-systems-backend-engineer/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/example-systems/_company.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-06-06-foobar-industries-frontend-developer/documents/2022-06-06-foobar-industries-frontend-developer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-06-06-foobar-industries-frontend-developer/documents/2022-06-06-foobar-industries-frontend-developer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-06-06-foobar-industries-frontend-developer/documents/2022-06-06-foobar-industries-frontend-developer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-06-06-foobar-industries-frontend-developer/documents/2022-06-06-foobar-industries-frontend-developer-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-06-06-foobar-industries-frontend-developer/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-11-20-foobar-industries-engineering-manager/documents/2022-11-20-foobar-industries-engineering-manager-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-11-20-foobar-industries-engineering-manager/documents/2022-11-20-foobar-industries-engineering-manager-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-11-20-foobar-industries-engineering-manager/documents/2022-11-20-foobar-industries-engineering-manager-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-11-20-foobar-industries-engineering-manager/documents/2022-11-20-foobar-industries-engineering-manager-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-11-20-foobar-industries-engineering-manager/documents/2022-11-20-foobar-industries-engineering-manager-doc5.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-11-20-foobar-industries-engineering-manager/documents/2022-11-20-foobar-industries-engineering-manager-doc6.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/2022-11-20-foobar-industries-engineering-manager/vacancy.md +13 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/foobar-industries/_company.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2022-10-07-kolokolchik-qa-engineer/documents/2022-10-07-kolokolchik-qa-engineer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2022-10-07-kolokolchik-qa-engineer/documents/2022-10-07-kolokolchik-qa-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2022-10-07-kolokolchik-qa-engineer/vacancy.md +13 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2023-06-11-kolokolchik-product-designer/documents/2023-06-11-kolokolchik-product-designer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2023-06-11-kolokolchik-product-designer/documents/2023-06-11-kolokolchik-product-designer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2023-06-11-kolokolchik-product-designer/documents/2023-06-11-kolokolchik-product-designer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2023-06-11-kolokolchik-product-designer/documents/2023-06-11-kolokolchik-product-designer-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2023-06-11-kolokolchik-product-designer/documents/2023-06-11-kolokolchik-product-designer-doc5.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2023-06-11-kolokolchik-product-designer/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2024-07-04-kolokolchik-technical-writer/documents/2024-07-04-kolokolchik-technical-writer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2024-07-04-kolokolchik-technical-writer/documents/2024-07-04-kolokolchik-technical-writer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2024-07-04-kolokolchik-technical-writer/documents/2024-07-04-kolokolchik-technical-writer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/2024-07-04-kolokolchik-technical-writer/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/kolokolchik/_company.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2022-02-19-mockup-media-unknown/documents/2022-02-19-mockup-media-unknown-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2022-02-19-mockup-media-unknown/documents/2022-02-19-mockup-media-unknown-doc2.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2022-02-19-mockup-media-unknown/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-01-13-mockup-media-unknown/documents/2025-01-13-mockup-media-unknown-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-01-13-mockup-media-unknown/documents/2025-01-13-mockup-media-unknown-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-01-13-mockup-media-unknown/documents/2025-01-13-mockup-media-unknown-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-01-13-mockup-media-unknown/documents/2025-01-13-mockup-media-unknown-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-01-13-mockup-media-unknown/documents/2025-01-13-mockup-media-unknown-doc5.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-01-13-mockup-media-unknown/documents/2025-01-13-mockup-media-unknown-doc6.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-01-13-mockup-media-unknown/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-04-25-mockup-media-unknown/documents/2025-04-25-mockup-media-unknown-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-04-25-mockup-media-unknown/documents/2025-04-25-mockup-media-unknown-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/2025-04-25-mockup-media-unknown/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/mockup-media/_company.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/oduvanchik/2024-03-20-oduvanchik-data-analyst/documents/2024-03-20-oduvanchik-data-analyst-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/oduvanchik/2024-03-20-oduvanchik-data-analyst/documents/2024-03-20-oduvanchik-data-analyst-doc2.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/oduvanchik/2024-03-20-oduvanchik-data-analyst/documents/2024-03-20-oduvanchik-data-analyst-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/oduvanchik/2024-03-20-oduvanchik-data-analyst/documents/2024-03-20-oduvanchik-data-analyst-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/oduvanchik/2024-03-20-oduvanchik-data-analyst/documents/2024-03-20-oduvanchik-data-analyst-doc5.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/oduvanchik/2024-03-20-oduvanchik-data-analyst/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/oduvanchik/_company.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sample-solutions/2022-08-05-sample-solutions-engineering-manager/documents/2022-08-05-sample-solutions-engineering-manager-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sample-solutions/2022-08-05-sample-solutions-engineering-manager/documents/2022-08-05-sample-solutions-engineering-manager-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sample-solutions/2022-08-05-sample-solutions-engineering-manager/documents/2022-08-05-sample-solutions-engineering-manager-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sample-solutions/2022-08-05-sample-solutions-engineering-manager/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sample-solutions/_company.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/2023-06-18-sandbox-systems-data-analyst/documents/2023-06-18-sandbox-systems-data-analyst-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/2023-06-18-sandbox-systems-data-analyst/documents/2023-06-18-sandbox-systems-data-analyst-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/2023-06-18-sandbox-systems-data-analyst/documents/2023-06-18-sandbox-systems-data-analyst-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/2023-06-18-sandbox-systems-data-analyst/documents/2023-06-18-sandbox-systems-data-analyst-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/2023-06-18-sandbox-systems-data-analyst/documents/2023-06-18-sandbox-systems-data-analyst-doc5.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/2023-06-18-sandbox-systems-data-analyst/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/2023-06-20-sandbox-systems-backend-engineer/documents/2023-06-20-sandbox-systems-backend-engineer-doc1.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/2023-06-20-sandbox-systems-backend-engineer/documents/2023-06-20-sandbox-systems-backend-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/2023-06-20-sandbox-systems-backend-engineer/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/sandbox-systems/_company.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/_company.md +7 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-multi-a/documents/search-fixture-multi-a-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-multi-a/vacancy.md +11 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-multi-b/documents/search-fixture-multi-b-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-multi-b/vacancy.md +11 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-paraphrase/documents/search-fixture-paraphrase-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-paraphrase/vacancy.md +11 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-terms/documents/search-fixture-terms-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-terms/documents/search-fixture-terms-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-terms/documents/search-fixture-terms-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/search-fixtures-corp/search-fixture-terms/vacancy.md +11 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2022-03-22-vaporware-studio-devops-engineer/documents/2022-03-22-vaporware-studio-devops-engineer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2022-03-22-vaporware-studio-devops-engineer/documents/2022-03-22-vaporware-studio-devops-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2022-03-22-vaporware-studio-devops-engineer/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2023-03-04-vaporware-studio-site-reliability-engineer/documents/2023-03-04-vaporware-studio-site-reliability-engineer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2023-03-04-vaporware-studio-site-reliability-engineer/documents/2023-03-04-vaporware-studio-site-reliability-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2023-03-04-vaporware-studio-site-reliability-engineer/documents/2023-03-04-vaporware-studio-site-reliability-engineer-doc3.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2023-03-04-vaporware-studio-site-reliability-engineer/documents/2023-03-04-vaporware-studio-site-reliability-engineer-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2023-03-04-vaporware-studio-site-reliability-engineer/documents/2023-03-04-vaporware-studio-site-reliability-engineer-doc5.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2023-03-04-vaporware-studio-site-reliability-engineer/documents/2023-03-04-vaporware-studio-site-reliability-engineer-doc6.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/2023-03-04-vaporware-studio-site-reliability-engineer/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/vaporware-studio/_company.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2024-11-20-widget-works-machine-learning-engineer/documents/2024-11-20-widget-works-machine-learning-engineer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2024-11-20-widget-works-machine-learning-engineer/documents/2024-11-20-widget-works-machine-learning-engineer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2024-11-20-widget-works-machine-learning-engineer/documents/2024-11-20-widget-works-machine-learning-engineer-doc3.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2024-11-20-widget-works-machine-learning-engineer/documents/2024-11-20-widget-works-machine-learning-engineer-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2024-11-20-widget-works-machine-learning-engineer/documents/2024-11-20-widget-works-machine-learning-engineer-doc5.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2024-11-20-widget-works-machine-learning-engineer/vacancy.md +14 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2025-09-08-widget-works-frontend-developer/documents/2025-09-08-widget-works-frontend-developer-doc1.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2025-09-08-widget-works-frontend-developer/documents/2025-09-08-widget-works-frontend-developer-doc2.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2025-09-08-widget-works-frontend-developer/documents/2025-09-08-widget-works-frontend-developer-doc3.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2025-09-08-widget-works-frontend-developer/documents/2025-09-08-widget-works-frontend-developer-doc4.md +8 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2025-09-08-widget-works-frontend-developer/documents/2025-09-08-widget-works-frontend-developer-doc5.md +9 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/2025-09-08-widget-works-frontend-developer/vacancy.md +15 -0
- vacancy_radar-0.1.0/tests/fixtures/vault/widget-works/_company.md +8 -0
- vacancy_radar-0.1.0/tests/index/test_build.py +552 -0
- vacancy_radar-0.1.0/tests/index/test_embed.py +77 -0
- vacancy_radar-0.1.0/tests/index/test_extract.py +224 -0
- vacancy_radar-0.1.0/tests/index/test_schema.py +82 -0
- vacancy_radar-0.1.0/tests/index/test_search.py +1006 -0
- vacancy_radar-0.1.0/tests/index/test_snippet.py +68 -0
- vacancy_radar-0.1.0/tests/index/test_store.py +49 -0
- vacancy_radar-0.1.0/tests/test_cli.py +1301 -0
- vacancy_radar-0.1.0/tests/test_config.py +225 -0
- vacancy_radar-0.1.0/tests/test_core.py +1920 -0
- vacancy_radar-0.1.0/tests/test_frontmatter.py +70 -0
- vacancy_radar-0.1.0/tests/test_ids.py +98 -0
- vacancy_radar-0.1.0/tests/test_import.py +38 -0
- vacancy_radar-0.1.0/tests/test_mcp_server.py +1449 -0
- vacancy_radar-0.1.0/tests/test_models.py +354 -0
- vacancy_radar-0.1.0/tests/test_packaging.py +125 -0
- vacancy_radar-0.1.0/tests/test_version.py +7 -0
- vacancy_radar-0.1.0/tests/vault/test_hashing.py +41 -0
- vacancy_radar-0.1.0/tests/vault/test_paths.py +93 -0
- vacancy_radar-0.1.0/tests/vault/test_reader.py +717 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format
|
|
4
|
+
follows [Keep a Changelog](https://keepachangelog.com/), and this
|
|
5
|
+
project uses [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-08-10
|
|
8
|
+
|
|
9
|
+
First release: a local-first job application tracker built around a
|
|
10
|
+
markdown vault, with hybrid search and an MCP server.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Vault model and reader.** A markdown vault is the source of truth —
|
|
15
|
+
typed frontmatter, stable derived ids, company and vacancy documents,
|
|
16
|
+
and a reader that collects warnings rather than failing on a single
|
|
17
|
+
malformed file. `vacancy-radar init` creates or idempotently adopts a
|
|
18
|
+
vault directory without touching existing content.
|
|
19
|
+
- **Derived LanceDB index.** Chunked documents with BM25 and vector
|
|
20
|
+
columns, rebuilt from the vault by `vacancy-radar reindex`; every
|
|
21
|
+
write reindexes its own effect eagerly, so results are searchable
|
|
22
|
+
immediately.
|
|
23
|
+
- **Hybrid retrieval.** Keyword, semantic, and hybrid search modes with
|
|
24
|
+
configurable fusion. The shipped defaults — linear-combination fusion
|
|
25
|
+
at `vector_weight` 0.5 — were chosen from measurement, reversing the
|
|
26
|
+
design's original RRF guess.
|
|
27
|
+
- **Evaluation harness** (`vacancy-radar eval`): 30 labelled queries
|
|
28
|
+
across seven categories scored with recall@k and MRR against the
|
|
29
|
+
committed fixture vault. See [docs/evaluation.md](docs/evaluation.md).
|
|
30
|
+
- **Read CLI**: `list`, `show`, `search`, and `doctor`, each with a Rich
|
|
31
|
+
table for humans and a stable `--json` shape for piping.
|
|
32
|
+
- **Write CLI**: `new`, `note`, `status set`, `add`, and `reindex`.
|
|
33
|
+
Every write is append-only or a validated status transition; there is
|
|
34
|
+
no delete command anywhere in the CLI.
|
|
35
|
+
- **PDF sidecar extraction** (`reindex --extract-sidecars`): extracts
|
|
36
|
+
text from PDFs under `documents/` into git-tracked `.pdf.md`
|
|
37
|
+
sidecars, so they are searchable by content. An encrypted or
|
|
38
|
+
unparseable PDF warns and is skipped rather than failing the reindex.
|
|
39
|
+
- **MCP server** (`vacancy-radar-mcp`): eleven tools matching `core.py`
|
|
40
|
+
one for one, two resources, and three prompts, over stdio for any MCP
|
|
41
|
+
client. Typed errors surface as structured results a calling model
|
|
42
|
+
can act on, never a crash.
|
|
43
|
+
- **Conversational import** via `find_existing` + `create_vacancy`, for
|
|
44
|
+
moving an existing tracker into a vault by talking to a model. See
|
|
45
|
+
[docs/import-guide.md](docs/import-guide.md).
|
|
46
|
+
- **Published to PyPI.** `uvx vacancy-radar` and `uv tool install
|
|
47
|
+
vacancy-radar` expose the CLI, and `uvx --from vacancy-radar
|
|
48
|
+
vacancy-radar-mcp` the MCP server — no clone and no `uv.lock`
|
|
49
|
+
required. The distribution carries full landing-page metadata and an
|
|
50
|
+
SPDX `MIT` license expression, with the LICENSE file shipped in both
|
|
51
|
+
the wheel and the sdist.
|
|
52
|
+
- **Release automation** (`.github/workflows/release.yml`): a
|
|
53
|
+
tag-triggered release that builds once, verifies the built wheel by
|
|
54
|
+
installing and running it in a clean environment with no repository
|
|
55
|
+
checkout, and only then uploads it via PyPI Trusted Publishing. No
|
|
56
|
+
index credential is stored anywhere. A `workflow_dispatch` input runs
|
|
57
|
+
the same chain against TestPyPI as a dry run. See
|
|
58
|
+
[docs/releasing.md](docs/releasing.md).
|
|
59
|
+
- **Packaging test** (`tests/test_packaging.py`): asserts the built
|
|
60
|
+
distribution's entry points, license file, and landing-page metadata
|
|
61
|
+
on every test run, so a packaging regression fails CI instead of
|
|
62
|
+
degrading a release.
|
|
63
|
+
- CI on pushes to `main` and pull requests: pre-commit hooks and the
|
|
64
|
+
full test suite, with the embedding model cached by model name.
|
|
65
|
+
|
|
66
|
+
[0.1.0]: https://github.com/Akay7/vacancy-radar/releases/tag/v0.1.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Egor Poderiagin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vacancy-radar
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local-first job application tracker with hybrid search and an MCP server.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Akay7/vacancy-radar
|
|
6
|
+
Project-URL: Repository, https://github.com/Akay7/vacancy-radar
|
|
7
|
+
Project-URL: Issues, https://github.com/Akay7/vacancy-radar/issues
|
|
8
|
+
Author-email: Egor Poderiagin <egor@crazyrussian.pro>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: hybrid-search,job-search,job-tracker,lancedb,markdown,mcp
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Office/Business
|
|
19
|
+
Classifier: Topic :: Text Processing :: Indexing
|
|
20
|
+
Requires-Python: >=3.12
|
|
21
|
+
Requires-Dist: fastembed>=0.8.0
|
|
22
|
+
Requires-Dist: lancedb>=0.36.0
|
|
23
|
+
Requires-Dist: mcp>=2.0.0
|
|
24
|
+
Requires-Dist: pydantic>=2.13.4
|
|
25
|
+
Requires-Dist: pypdf>=6.14.2
|
|
26
|
+
Requires-Dist: rich>=15.0.0
|
|
27
|
+
Requires-Dist: ruamel-yaml>=0.19.1
|
|
28
|
+
Requires-Dist: text-unidecode>=1.3
|
|
29
|
+
Requires-Dist: typer>=0.27.1
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# vacancy-radar
|
|
33
|
+
|
|
34
|
+
A local-first job application tracker. A markdown vault is the source of
|
|
35
|
+
truth; a derived LanceDB index provides hybrid BM25 + vector search; an MCP
|
|
36
|
+
server exposes read/write tools to any LLM client.
|
|
37
|
+
|
|
38
|
+
## Status
|
|
39
|
+
|
|
40
|
+
Vault, index, retrieval, CLI (read and write), and MCP server are all
|
|
41
|
+
implemented. Stage 9 (import) is too — conversationally, via
|
|
42
|
+
`create_vacancy`/`find_existing` over MCP (see
|
|
43
|
+
[docs/import-guide.md](docs/import-guide.md)), not an xlsx/CSV
|
|
44
|
+
importer; this project ships no spreadsheet parser or interchange
|
|
45
|
+
format.
|
|
46
|
+
|
|
47
|
+
## How CLI and MCP fit together
|
|
48
|
+
|
|
49
|
+
Two front doors, one back end: a human runs the CLI, an LLM client
|
|
50
|
+
calls MCP tools, and both go through the same `core.py` functions onto
|
|
51
|
+
the same markdown vault and LanceDB index — neither interface has any
|
|
52
|
+
capability, or any data, the other doesn't see.
|
|
53
|
+
|
|
54
|
+
```mermaid
|
|
55
|
+
flowchart TD
|
|
56
|
+
subgraph CLI["Human — terminal (vacancy-radar CLI)"]
|
|
57
|
+
direction TB
|
|
58
|
+
C1["init\ncreate the vault"]
|
|
59
|
+
C2["new\ncreate a vacancy"]
|
|
60
|
+
C3["add / note\nattach documents & notes"]
|
|
61
|
+
C4["status set\nmove it through the pipeline"]
|
|
62
|
+
C5["list / show / search\nread it back"]
|
|
63
|
+
C1 --> C2 --> C3 --> C4 --> C5
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
subgraph MCP["LLM client — MCP tools (vacancy-radar-mcp)"]
|
|
67
|
+
direction TB
|
|
68
|
+
M1["find_existing\ncheck before creating"]
|
|
69
|
+
M2["create_vacancy\n(conversational import)"]
|
|
70
|
+
M3["add_document / append_note"]
|
|
71
|
+
M4["set_status"]
|
|
72
|
+
M5["list_vacancies / get_vacancy / search"]
|
|
73
|
+
M1 --> M2 --> M3 --> M4 --> M5
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
C5 --> Vault[("Markdown vault\n+ LanceDB index")]
|
|
77
|
+
M5 --> Vault
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`init` and `reindex` are CLI-only (see their sections below for why);
|
|
81
|
+
everything else on both sides is the same underlying operation,
|
|
82
|
+
exposed twice. The CLI trusts the human typing the command; the MCP
|
|
83
|
+
tools add the extra checks a model calling them unsupervised needs —
|
|
84
|
+
`create_vacancy` never deduplicates on its own (call `find_existing`
|
|
85
|
+
first), and every typed error comes back as something the model reads
|
|
86
|
+
and can act on in the same turn, not a crash.
|
|
87
|
+
|
|
88
|
+
## Install
|
|
89
|
+
|
|
90
|
+
### Use it
|
|
91
|
+
|
|
92
|
+
You need [uv](https://docs.astral.sh/uv/). Nothing else — no clone, no
|
|
93
|
+
`uv.lock`.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Run it once, without installing anything permanently.
|
|
97
|
+
uvx vacancy-radar --version
|
|
98
|
+
|
|
99
|
+
# Or put `vacancy-radar` on PATH for good.
|
|
100
|
+
uv tool install vacancy-radar
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The MCP server ships in the same distribution, but its script name
|
|
104
|
+
differs from the distribution name, so it needs `--from` (see
|
|
105
|
+
[MCP server](#mcp-server) below for the client config):
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
uvx --from vacancy-radar vacancy-radar-mcp --vault /path/to/vault
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Expect the first run to be slow.** The dependency set is large
|
|
112
|
+
(`lancedb` and `fastembed` are hundreds of megabytes resolved), and the
|
|
113
|
+
first `search` downloads an embedding model on top of that. Both are
|
|
114
|
+
cached afterward — a slow first run is the download, not a hang.
|
|
115
|
+
|
|
116
|
+
### Work on it
|
|
117
|
+
|
|
118
|
+
For contributing to vacancy-radar itself, from a clone:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv sync --all-groups
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Every command example below is written in this contributor form, with a
|
|
125
|
+
`uv run` prefix. **If you installed the tool, drop the `uv run`** —
|
|
126
|
+
`uv run vacancy-radar list` becomes `vacancy-radar list`.
|
|
127
|
+
|
|
128
|
+
## Getting started
|
|
129
|
+
|
|
130
|
+
Every command below expects a vault to already exist at `VAULT_PATH`
|
|
131
|
+
(or an explicit path, where the command takes one). Create one first:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
uv run vacancy-radar init /path/to/vault
|
|
135
|
+
export VAULT_PATH=/path/to/vault
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`init` is idempotent - running it again against the same path is a
|
|
139
|
+
no-op, not an error - and it never touches anything already in a
|
|
140
|
+
directory it adopts (see [design.md](openspec/changes/vault-init/
|
|
141
|
+
design.md) for the full rationale).
|
|
142
|
+
|
|
143
|
+
## Usage
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
uv run vacancy-radar --version
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`list`, `show`, `search`, and `doctor` are read-only: they never write to
|
|
150
|
+
the vault or the index. Every command prints a Rich table for humans by
|
|
151
|
+
default; add `--json` for a machine-readable, stable, documented shape
|
|
152
|
+
suitable for piping (see `openspec/changes/archive/2026-08-06-cli-read/
|
|
153
|
+
design.md`'s `--json` contract).
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# List vacancies, optionally filtered (--status, --company, --since,
|
|
157
|
+
# --needs-review, --stale-days), sorted by last activity.
|
|
158
|
+
uv run vacancy-radar list --status applied --status interview
|
|
159
|
+
|
|
160
|
+
# Show one vacancy or company - which kind it is is auto-detected.
|
|
161
|
+
uv run vacancy-radar show acme-corp
|
|
162
|
+
|
|
163
|
+
# Search the vault's index (see "Retrieval evaluation" below);
|
|
164
|
+
# --scores prints each hit's keyword/semantic rank and fused score.
|
|
165
|
+
uv run vacancy-radar search "backend engineer" --scores
|
|
166
|
+
|
|
167
|
+
# Report vault and index health: marker, index freshness, embedding
|
|
168
|
+
# model availability, and every warning collected while reading.
|
|
169
|
+
uv run vacancy-radar doctor
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Writing
|
|
173
|
+
|
|
174
|
+
`note`, `status set`, `add`, `new`, and `reindex` write to the vault.
|
|
175
|
+
Every write is append-only or a validated status transition (see
|
|
176
|
+
`openspec/changes/archive/2026-08-06-cli-write/design.md`) - nothing
|
|
177
|
+
here deletes or overwrites existing content, and there is no delete
|
|
178
|
+
command anywhere in the CLI. `note`, `status set`, and `add` accept a
|
|
179
|
+
vacancy by id, company name, or unambiguous fuzzy match, resolved the
|
|
180
|
+
same way `show` resolves its argument; an ambiguous match prints the
|
|
181
|
+
candidates and exits non-zero without writing anything. `--json`
|
|
182
|
+
follows the same stable, documented-shape convention as the read
|
|
183
|
+
commands above.
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# A vacancy argument is an id, a company name/slug (if it resolves to
|
|
187
|
+
# exactly one vacancy), or an unambiguous fuzzy match - the same rule
|
|
188
|
+
# `show` uses. A company with several vacancies needs the vacancy id.
|
|
189
|
+
|
|
190
|
+
# Append a dated note. The filename is always derived from the date -
|
|
191
|
+
# never something you (or an LLM, at a later stage) supply.
|
|
192
|
+
uv run vacancy-radar note 2022-03-22-acme-corp-backend-engineer \
|
|
193
|
+
"Called the recruiter, no news yet."
|
|
194
|
+
|
|
195
|
+
# Move a vacancy's status. Backward transitions need --force; the first
|
|
196
|
+
# move off 'found' needs --applied-date.
|
|
197
|
+
uv run vacancy-radar status set 2022-03-22-acme-corp-backend-engineer \
|
|
198
|
+
applied --applied-date 2026-01-15
|
|
199
|
+
uv run vacancy-radar status set 2022-03-22-acme-corp-backend-engineer \
|
|
200
|
+
found --force
|
|
201
|
+
|
|
202
|
+
# File a *text* document (posting, email, note, or takehome) from a
|
|
203
|
+
# file or stdin. --external-id makes re-filing the same source (e.g.
|
|
204
|
+
# the same email thread) a no-op instead of a duplicate. `--file`/
|
|
205
|
+
# `--stdin` read UTF-8 text - binary content (a PDF) fails with a
|
|
206
|
+
# clear error naming the alternative below, not a crash.
|
|
207
|
+
uv run vacancy-radar add 2022-03-22-acme-corp-backend-engineer \
|
|
208
|
+
--kind email --title "Recruiter reply" --date 2026-01-16 \
|
|
209
|
+
--external-id gmail-thread-42 --stdin < email.txt
|
|
210
|
+
|
|
211
|
+
# Create a new vacancy (and its company directory, if new). --url is
|
|
212
|
+
# optional - omit it when the source has no link at all (e.g. a
|
|
213
|
+
# recruiter sent only a PDF attachment).
|
|
214
|
+
uv run vacancy-radar new --company "Acme Corp" --role "Backend Engineer" \
|
|
215
|
+
--url https://jobs.acme.example/1 --found-date 2026-01-10
|
|
216
|
+
|
|
217
|
+
# Rebuild the index from the vault's current state. Not required for
|
|
218
|
+
# ordinary use - every write above already reindexes its own effect
|
|
219
|
+
# eagerly, before returning, so it's searchable immediately.
|
|
220
|
+
uv run vacancy-radar reindex
|
|
221
|
+
|
|
222
|
+
# Extract text from any PDF under documents/ into a git-tracked
|
|
223
|
+
# <filename>.pdf.md sidecar, so it's searchable by content, not only
|
|
224
|
+
# by filename. Off by default - a build never silently creates sidecar
|
|
225
|
+
# files; pass this explicitly whenever a PDF was added or changed.
|
|
226
|
+
uv run vacancy-radar reindex --extract-sidecars
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### Attaching a PDF
|
|
230
|
+
|
|
231
|
+
There is no CLI command for filing a PDF the way `add` files text -
|
|
232
|
+
copy it directly into the vacancy's `documents/` directory, then
|
|
233
|
+
reindex with extraction:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
cp ~/Downloads/posting.pdf \
|
|
237
|
+
/path/to/vault/acme-corp/2022-03-22-acme-corp-backend-engineer/documents/
|
|
238
|
+
uv run vacancy-radar reindex --extract-sidecars
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
This registers the PDF as a document (`kind: takehome`, `title` set to
|
|
242
|
+
the filename, `date` set to the vacancy's `found_date` - none
|
|
243
|
+
independently settable this way; a posting or interview-prep PDF is
|
|
244
|
+
filed the same way, just under that `kind`) and writes a
|
|
245
|
+
`<filename>.pdf.md` sidecar containing its extracted text, so it's
|
|
246
|
+
searchable by content afterward. An encrypted or unparseable PDF fails
|
|
247
|
+
extraction without crashing the reindex - a warning naming the file
|
|
248
|
+
prints in `reindex`'s output (and appears under `--json`'s `warnings`
|
|
249
|
+
field too).
|
|
250
|
+
|
|
251
|
+
## MCP server
|
|
252
|
+
|
|
253
|
+
`vacancy-radar-mcp` exposes the same `core.py` functions the CLI above
|
|
254
|
+
calls, as MCP tools/resources/prompts over stdio, for any MCP client
|
|
255
|
+
(Claude Desktop, etc.) - see `openspec/changes/mcp-server/design.md`
|
|
256
|
+
for the full rationale.
|
|
257
|
+
|
|
258
|
+
Point your client at the published distribution — no clone required.
|
|
259
|
+
For Claude Desktop, that is `claude_desktop_config.json`:
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"mcpServers": {
|
|
264
|
+
"vacancy-radar": {
|
|
265
|
+
"command": "uvx",
|
|
266
|
+
"args": [
|
|
267
|
+
"--from", "vacancy-radar",
|
|
268
|
+
"vacancy-radar-mcp",
|
|
269
|
+
"--vault", "/path/to/vault"
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
`--from vacancy-radar` is required, not decorative: `uvx` resolves a
|
|
277
|
+
*distribution* named after the command it is given, and the script here
|
|
278
|
+
is `vacancy-radar-mcp` while the distribution is `vacancy-radar`. A
|
|
279
|
+
bare `uvx vacancy-radar-mcp` looks for a distribution that does not
|
|
280
|
+
exist.
|
|
281
|
+
|
|
282
|
+
For Claude Code, register the same command with `claude mcp add`
|
|
283
|
+
instead of editing JSON by hand:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
claude mcp add vacancy-radar -- \
|
|
287
|
+
uvx --from vacancy-radar vacancy-radar-mcp --vault /path/to/vault
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
If you have installed it persistently with `uv tool install
|
|
291
|
+
vacancy-radar`, `vacancy-radar-mcp` is already on PATH and the config's
|
|
292
|
+
`command` can be that directly, with just `["--vault", "/path/to/vault"]`
|
|
293
|
+
as args.
|
|
294
|
+
|
|
295
|
+
Working on the server itself, from a clone (after `uv sync
|
|
296
|
+
--all-groups`):
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
uv run vacancy-radar-mcp --vault /path/to/vault
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**Vault path**: `--vault` if given, else the `VAULT_PATH` environment
|
|
303
|
+
variable; neither present fails startup naming both. MCP's client-
|
|
304
|
+
supplied-roots capability is deliberately not used here - it is
|
|
305
|
+
deprecated as of the protocol revision the MCP Python SDK speaks by
|
|
306
|
+
default (2026-07-28, SEP-2577), so `--vault`/`VAULT_PATH` are the only
|
|
307
|
+
two ways to point the server at a vault, exactly like configuring any
|
|
308
|
+
other stdio MCP server.
|
|
309
|
+
|
|
310
|
+
**Eleven tools**, matching `core.py`'s functions one for one - argument
|
|
311
|
+
marshalling only, no filtering/sorting/business logic of its own:
|
|
312
|
+
|
|
313
|
+
| tool | delegates to |
|
|
314
|
+
| ---- | ------------- |
|
|
315
|
+
| `list_vacancies` | `core.list_vacancies` |
|
|
316
|
+
| `get_company` | `core.get_company` |
|
|
317
|
+
| `get_vacancy` | `core.get_vacancy` |
|
|
318
|
+
| `search` | `core.search` |
|
|
319
|
+
| `read_document` | `core.read_document` |
|
|
320
|
+
| `resolve` | `core.resolve` |
|
|
321
|
+
| `find_existing` | `core.find_existing` |
|
|
322
|
+
| `append_note` | `core.append_note` |
|
|
323
|
+
| `set_status` | `core.set_status` |
|
|
324
|
+
| `add_document` | `core.add_document` |
|
|
325
|
+
| `create_vacancy` | `core.create_vacancy` |
|
|
326
|
+
|
|
327
|
+
`reindex` is deliberately **not** exposed - every write tool already
|
|
328
|
+
refreshes the index itself, and there's no legitimate reason for a
|
|
329
|
+
client-connected model to trigger a full rebuild (design.md's exposure
|
|
330
|
+
decision). `create_vacancy` *is* exposed, for conversational import
|
|
331
|
+
(see [docs/import-guide.md](docs/import-guide.md)): it does not
|
|
332
|
+
deduplicate, so its own tool description tells a calling model to call
|
|
333
|
+
`find_existing` first and only create when that returns no match.
|
|
334
|
+
`search`'s description tells the model to prefer `mode="keyword"` for
|
|
335
|
+
exact-name/proper-noun queries and leave `mode` unset (hybrid)
|
|
336
|
+
otherwise, citing the measured numbers in "Retrieval evaluation" below
|
|
337
|
+
- without that guidance a model defaults to hybrid for everything and
|
|
338
|
+
the per-category tuning goes unused. A typed `core.py` error (an
|
|
339
|
+
ambiguous match, an invalid status transition, a nonexistent vacancy)
|
|
340
|
+
surfaces as a structured tool result the calling model can read and
|
|
341
|
+
act on, never a raw crash.
|
|
342
|
+
|
|
343
|
+
**Two resources**: `vacancy-radar://companies` (every company's slug,
|
|
344
|
+
display name, and vacancy count) and `vacancy-radar://statuses` (every
|
|
345
|
+
status and the transitions permitted from it, read live from
|
|
346
|
+
`models.py`).
|
|
347
|
+
|
|
348
|
+
**Three prompts**: `prep_interview(company)` (dossier, postings, prior
|
|
349
|
+
notes, take-homes), `draft_reply(vacancy_id)` (prior correspondence, to
|
|
350
|
+
match tone), and `weekly_review()` (stale applications, pending
|
|
351
|
+
take-homes, vacancies tagged `needs_review`). An unresolved or
|
|
352
|
+
ambiguous `company`/`vacancy_id` returns a message saying so - never a
|
|
353
|
+
fabricated dossier.
|
|
354
|
+
|
|
355
|
+
## Development
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
uv run pytest
|
|
359
|
+
uv run ruff check .
|
|
360
|
+
uv run ruff format --check .
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Pre-commit hooks
|
|
364
|
+
|
|
365
|
+
Install the git hooks once per clone so lint/format issues are caught
|
|
366
|
+
before you commit (the same checks CI runs):
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
uv run pre-commit install
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Run them on demand against all files:
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
uv run pre-commit run --all-files
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Retrieval evaluation
|
|
379
|
+
|
|
380
|
+
Measured with `eval/`'s harness: 30 labelled queries (`eval/queries.yaml`,
|
|
381
|
+
across seven categories) run against the committed fixture vault
|
|
382
|
+
(`tests/fixtures/vault/`), scored with `recall_at_k`/`mrr` over each
|
|
383
|
+
mode's top 5 results. Reproduce it with `uv run vacancy-radar eval`.
|
|
384
|
+
|
|
385
|
+
**Overall, by mode:**
|
|
386
|
+
|
|
387
|
+
| mode | vector_weight | fusion | recall@5 | MRR |
|
|
388
|
+
| ---- | -------------- | ------------------- | -------- | ----- |
|
|
389
|
+
| keyword | — | — | 0.761 | 0.675 |
|
|
390
|
+
| semantic | — | — | 0.678 | 0.583 |
|
|
391
|
+
| hybrid | 0.5 | rrf | 0.672 | 0.541 |
|
|
392
|
+
| hybrid (**shipped default**) | 0.5 | linear_combination | 0.794 | 0.687 |
|
|
393
|
+
|
|
394
|
+
**Per category, keyword vs. semantic vs. the shipped hybrid default (recall@5):**
|
|
395
|
+
|
|
396
|
+
| category | keyword | semantic | hybrid (0.5, linear_combination) |
|
|
397
|
+
| ------------ | ----- | ----- | ----- |
|
|
398
|
+
| exact_name | 1.000 | 0.800 | 1.000 |
|
|
399
|
+
| technical | 0.800 | 0.800 | 1.000 |
|
|
400
|
+
| paraphrase | 0.250 | 0.750 | 0.250 |
|
|
401
|
+
| temporal | 1.000 | 0.250 | 1.000 |
|
|
402
|
+
| multi_result | 0.417 | 0.250 | 0.417 |
|
|
403
|
+
| filtered | 0.792 | 0.833 | 0.792 |
|
|
404
|
+
| negative | 1.000 | 1.000 | 1.000 |
|
|
405
|
+
| **overall** | **0.761** | **0.678** | **0.794** |
|
|
406
|
+
|
|
407
|
+
Keyword dominates `exact_name` (company/recruiter proper nouns) exactly
|
|
408
|
+
as hypothesized at stage 4, and semantic strictly dominates `paraphrase`
|
|
409
|
+
(queries sharing no content word with their target) — the one category
|
|
410
|
+
keyword structurally cannot serve at all. Both single modes are weak on
|
|
411
|
+
`multi_result` and one of them is weak on `temporal`, which top-5
|
|
412
|
+
recall@5 punishes when several correct documents compete for five
|
|
413
|
+
slots. **The fusion strategy default did not survive contact with
|
|
414
|
+
measurement**: RRF (stage 4's original default) *underperforms plain
|
|
415
|
+
keyword search* on this corpus — 0.672 vs. 0.761 overall recall@5,
|
|
416
|
+
identical across every `vector_weight` since RRF is rank-based and
|
|
417
|
+
weight-agnostic — while Linear Combination fusion at `vector_weight`
|
|
418
|
+
0.3–0.6 ties for the best result on every metric checked (0.3–0.6 score
|
|
419
|
+
identically; 0.7 ties on recall@5 but drops on MRR). `default_vector_weight`
|
|
420
|
+
is set to `0.5`, the middle of that tied band, and `fusion_strategy` to
|
|
421
|
+
`LINEAR_COMBINATION` — both a reversal of stage 4's guess, not a
|
|
422
|
+
confirmation of it. See `config.py`'s `SearchConfig` docstring and this
|
|
423
|
+
change's `tasks.md` (section 5) for the full per-category sweep.
|
|
424
|
+
|
|
425
|
+
**Limitations.** These numbers characterize the retrieval *design*
|
|
426
|
+
against a synthetic, generator-produced fixture vault — not a real
|
|
427
|
+
corpus of job-search correspondence. `tests/fixtures/generate.py`'s
|
|
428
|
+
proper nouns, phrasing patterns, and document lengths are artifacts of
|
|
429
|
+
the generator, not a sample of real vacancies, emails, or notes. Treat
|
|
430
|
+
this table as justification for a *default*, not a claim that
|
|
431
|
+
generalizes. See [docs/evaluation.md](docs/evaluation.md) for the
|
|
432
|
+
procedure to run a second eval against your own real vault after
|
|
433
|
+
import, and for which numbers to trust when retuning
|
|
434
|
+
`SEARCH_DEFAULT_VECTOR_WEIGHT`/`SEARCH_FUSION_STRATEGY` for your own
|
|
435
|
+
deployment.
|
|
436
|
+
|
|
437
|
+
**Future work, not built here.** `multi_result` and `temporal` recall
|
|
438
|
+
suggest a reranker could help beyond what fusion-weight tuning alone
|
|
439
|
+
achieves — not implemented in this change per its constraints. Whether
|
|
440
|
+
`negative`-category queries should return a score-floor-suppressed
|
|
441
|
+
empty result instead of five low-relevance ones is a real product
|
|
442
|
+
question, deliberately left open (see design.md): it would change
|
|
443
|
+
`search()`'s return contract and belongs in its own change if a real
|
|
444
|
+
vault's negative-query scores ever turn out close enough to real hits
|
|
445
|
+
to mislead.
|
|
446
|
+
|
|
447
|
+
## License
|
|
448
|
+
|
|
449
|
+
MIT — see [LICENSE](LICENSE).
|