> built 2026-10-14 02:29 UTC from 2b5ebd0 (main) · hired 0.0.23. Details: build_info.json

# index.html.md

<!-- generated by epythet -->

# hired

AI-assisted job applications: tailor a resume to a job, render it (PDF/HTML),
search jobs across boards, and support the application (matching, ATS check,
cover letter, tracking).

## Install

`pip install hired` gives you the core resume pipeline and the workflow helpers;
optional features are extras:

| Install             | Adds                                                                            |
|---------------------|---------------------------------------------------------------------------------|
| `pip install hired` | core: resume tailoring + HTML rendering, matching, ATS, cover letters, tracking |
| `hired[pdf]`        | PDF rendering via WeasyPrint (needs system libs: cairo/pango)                   |
| `hired[rendercv]`   | LaTeX/Typst-quality PDFs via rendercv                                           |
| `hired[search]`     | multi-board job search (jobspy)                                                 |
| `hired[ai]`         | real LLM resume tailoring (openai)                                              |
| `hired[all]`        | everything above                                                                |

`import hired` works with just the core deps — the heavy integrations load lazily.

## Quick start — tailor and render a resume

```python
from hired import mk_content_for_resume, mk_resume

# candidate / job can be dicts, file paths (json/yaml), or a JobResult
content = mk_content_for_resume("candidate.json", "job.txt")
pdf_bytes = mk_resume(content, {"format": "pdf", "theme": "default"})
```

By default this uses a pass-through agent. For real AI tailoring, install
`hired[ai]` and inject the LLM agent (set `OPENAI_API_KEY`):

```python
from hired import LLMResumeAgent

content = mk_content_for_resume("candidate.json", "job.txt", agent=LLMResumeAgent())
```

## Quick start — job search

```python
from hired import JobSources, SearchCriteria

sources = JobSources()
results = sources.search_all(
    SearchCriteria(
        query="python developer", location="San Francisco, CA", results_wanted=20
    )
)
for job in results:
    print(f"{job.title} at {job.company} — {job.job_url}")
```

For detailed documentation, see [JOB_SEARCH_README.md]()

## Features

### 1. Job Search (NEW!)

- **Multi-Source Search**: Search jobs across Indeed, LinkedIn, Glassdoor, ZipRecruiter, Google, USAJobs, and Adzuna
- **Unified Interface**: Consistent API across all job sources
- **Plugin Architecture**: Easily extend with custom job sources
- **Free & Paid Options**: Mix of free scrapers and API-based sources
- See [JOB_SEARCH_README.md]() for detailed documentation

### 2. Content Generation

- **AI-Driven Content**: Automatically generate resume content by analyzing candidate profiles and job descriptions.
- **Flexible Sources**: Supports JSON, YAML, and Python dictionaries as input sources.

### 3. Validation

- **JSON Resume Schema**: Ensures compliance with the [JSON Resume schema](https://jsonresume.org/schema/).
- **Strict and Permissive Modes**: Validate content strictly or allow flexibility for missing fields.
- **Pruning**: Automatically removes `None` values to ensure schema compliance.

### 4. Rendering

- **HTML and PDF**: Render resumes as HTML or PDF.
- **Template-Based Themes**: Use Jinja2 templates for customizable themes (e.g., `default`, `minimal`).
- **Optional WeasyPrint Integration**: Generate professional PDFs with WeasyPrint if installed.
- **Fallback PDF Builder**: Minimal PDF generation without external dependencies.
- **Empty Section Omission**: Automatically skips rendering empty sections.

# hired - resume agent

The `resume_agent` is an AI-powered system designed to assist in creating tailored resumes. It operates in manual, semi-autonomous, and fully autonomous modes, providing flexibility and control over the resume generation process.

## 1. Setup: Providing Job and Candidate Information

First, define the job you’re applying for and the candidate’s background. This information will be the foundation for the AI’s work.

```python
from hired.resume_agent import ResumeSession, ResumeExpertAgent, LLMConfig

# Define the job description
job_info = """
Senior Machine Learning Engineer at InnovateTech

We are seeking an experienced ML engineer to join our dynamic team. The ideal
candidate will have a strong background in building and deploying machine
learning models, with expertise in NLP and computer vision. Responsibilities
include designing and implementing ML pipelines, collaborating with
cross-functional teams, and driving innovation in our products.
"""

# Summarize the candidate's experience
candidate_info = """
- 7+ years of experience as a software and machine learning engineer.
- Proficient in Python, TensorFlow, and PyTorch.
- Led the development of a real-time recommendation engine, increasing user
  engagement by 20%.
- Designed and deployed a computer vision system for quality control in
  manufacturing, reducing defects by 15%.
- Published two papers on NLP in top-tier conferences.
"""

# Configure the LLM to be used by the agent
# (This is a conceptual example; you would integrate your preferred LLM provider)
llm_config = LLMConfig(model="gpt-4-turbo")
```

## 2. Manual Mode: Interactive Resume Building

In manual mode, you have direct control over the resume creation process. You can chat with the `ResumeSession` to expand on your achievements, distill verbose descriptions into impactful bullet points, or analyze how your experience matches the job. This is useful for users who want to guide the AI step-by-step and retain full control.

```python
# Create a session in manual mode
session = ResumeSession(
    job_info=job_info,
    candidate_info=candidate_info,
    llm_config=llm_config,
)

# Start a chat to expand on a specific point
response = session.chat(
    "Expand on the recommendation engine project. "
    "Mention the use of collaborative filtering and A/B testing."
)
print("AI-EXPANDED ACHIEVEMENT:")
print(response)

# You can continue the conversation to refine other sections
response = session.chat(
    "Now, distill the computer vision project description into a single, "
    "impactful resume bullet point."
)
print("\nAI-DISTILLED BULLET POINT:")
print(response)
```

## 3. Semi-Automatic Mode: Plan, Review, and Execute

For a more guided but still controlled approach, you can ask the `ResumeExpertAgent` to propose a plan. You can review this plan, make changes if needed, and then command the agent to execute it. This balances automation with human oversight.

```python
# Create an expert agent
agent = ResumeExpertAgent(llm_config=llm_config)

# Propose a plan for creating the resume
plan = agent.propose_plan(session)

print("PROPOSED PLAN:")
for step in plan.steps:
    print(f"- {step.id}: {step.description} (Depends on: {step.dependencies})")

# After reviewing (and optionally editing) the plan, execute it
# The agent will perform the steps, like analyzing the job,
# drafting sections, and matching skills.
results = agent.execute_plan(session, plan)

if results["success"]:
    print("\nPlan executed successfully!")
    # The final resume content is stored in the session state
    final_resume = session.state.get("final_resume_content")
    # print(final_resume)
```

## 4. Fully Automatic Mode: End-to-End Resume Generation

In the fully automatic mode, the `ResumeExpertAgent` handles the entire process from analysis to final output. It creates and executes its own plan to generate a resume tailored to the job description. This is the fastest way to get a first draft.

```python
# The agent handles everything autonomously
final_resume_content = agent.create_resume(session)

print("--- AUTONOMOUSLY GENERATED RESUME ---")
print(final_resume_content)
print("------------------------------------")
```

<p class="epythet-aggregates">This documentation as a single file: <a href="hired.md">hired.md</a> (Markdown, for agents).</p>


# _autosummary/hired.alignment.base.html.md

# hired.alignment.base

Schemas for JD-vs-candidate alignment analysis.

A job description is decomposed into [`Requirement`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Requirement) records; each is
analysed into a [`RequirementRecord`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.RequirementRecord) carrying a three-valued
[`MatchState`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.MatchState), a [`Bucket`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Bucket), grounding
[`Evidence`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Evidence), and the fields the elicitation loop needs. The whole analysis
is an [`AlignmentReport`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.AlignmentReport) — verdict-first, evidence-quoted, banded (never a
single false-precision percentage).

See `misc/docs/DESIGN.md` §6.

### Classes

| [`AILeverage`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.AILeverage)(\*values)        | How much the candidate's standing AI-agent capability lowers the ramp.   |
|------------------------------------------------------------------------------|--------------------------------------------------------------------------|
| [`AlignmentReport`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.AlignmentReport)(\*\*data)   | A complete, verdict-first alignment analysis for one JD.                 |
| [`Bucket`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Bucket)(\*values)            | The four alignment buckets.                                              |
| [`Clarification`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Clarification)(\*\*data)     | A question to ask the candidate to resolve a decision-relevant unknown.  |
| [`CloseMethod`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.CloseMethod)(\*values)       |                                                                          |
| [`Closeability`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Closeability)(\*values)      | How hard a gap is to close (Axis B), after the AI-leverage modifier.     |
| [`Evidence`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Evidence)(\*\*data)          | A verbatim grounding span for a match judgment.                          |
| [`FieldCompleteness`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.FieldCompleteness)(\*values) | Local closed-world flag: may a missing value be read as a real negative? |
| [`FitBand`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.FitBand)(\*values)           |                                                                          |
| [`InterviewPrep`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.InterviewPrep)(\*\*data)     |                                                                          |
| [`MatchType`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.MatchType)(\*values)         | How the candidate's background relates to the requirement (Axis A).      |
| [`NextAction`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.NextAction)(\*\*data)        |                                                                          |
| [`Recommendation`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Recommendation)(\*values)    |                                                                          |
| [`Requirement`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Requirement)(\*\*data)       | One atomic requirement extracted verbatim from a job description.        |
| [`RequirementClass`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.RequirementClass)(\*values)  | How decision-critical a requirement is.                                  |
| [`RequirementRecord`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.RequirementRecord)(\*\*data) | The analysis of one requirement against the candidate's knowledge.       |
| [`ScoreSummary`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.ScoreSummary)(\*\*data)      |                                                                          |
| [`SkillType`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.SkillType)(\*values)         |                                                                          |
| [`TimeToClose`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.TimeToClose)(\*values)       |                                                                          |
| [`Transferability`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Transferability)(\*values)   |                                                                          |
| [`Verdict`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Verdict)(\*\*data)           |                                                                          |

### *class* hired.alignment.base.AILeverage(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

How much the candidate’s standing AI-agent capability lowers the ramp.

Applies to *codified / knowledge-breadth* gaps, not tacit-judgment or
enduring-aptitude gaps (those it cannot rescue).

### *class* hired.alignment.base.AlignmentReport(\*\*data)

Bases: `BaseModel`

A complete, verdict-first alignment analysis for one JD.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.base.Bucket(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

The four alignment buckets.

### *class* hired.alignment.base.Clarification(\*\*data)

Bases: `BaseModel`

A question to ask the candidate to resolve a decision-relevant unknown.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.base.CloseMethod(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.base.Closeability(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

How hard a gap is to close (Axis B), after the AI-leverage modifier.

### *class* hired.alignment.base.Evidence(\*\*data)

Bases: `BaseModel`

A verbatim grounding span for a match judgment.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.base.FieldCompleteness(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Local closed-world flag: may a missing value be read as a real negative?

### *class* hired.alignment.base.FitBand(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.base.InterviewPrep(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.base.MatchType(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

How the candidate’s background relates to the requirement (Axis A).

### *class* hired.alignment.base.NextAction(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.base.Recommendation(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.base.Requirement(\*\*data)

Bases: `BaseModel`

One atomic requirement extracted verbatim from a job description.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.base.RequirementClass(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

How decision-critical a requirement is.

### *class* hired.alignment.base.RequirementRecord(\*\*data)

Bases: `BaseModel`

The analysis of one requirement against the candidate’s knowledge.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.base.ScoreSummary(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.base.SkillType(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.base.TimeToClose(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.base.Transferability(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.base.Verdict(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].


# _autosummary/hired.alignment.diff.html.md

# hired.alignment.diff

Deterministic diff between two alignment reports.

Used by the alignment-review workflow (heavy mode) to surface *what changed*
between an existing report and a freshly regenerated one — so the change set is
auditable and reviewable before anything is applied. Requirements are matched by
their verbatim text (stable across regenerations); the diff reports bucket moves,
verdict changes, and added/removed requirements and clarifications.

See `misc/docs/DESIGN.md` §6 and the alignment-review agent.

### Functions

| [`diff_reports`](_autosummary/hired.alignment.diff.html.md#hired.alignment.diff.diff_reports)(old, new)   | Return a structured diff of two alignment-report dicts.                                                   |
|---------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|
| [`summarize_diff`](_autosummary/hired.alignment.diff.html.md#hired.alignment.diff.summarize_diff)(diff)     | A short human-readable summary of [`diff_reports()`](_autosummary/hired.alignment.diff.html.md#hired.alignment.diff.diff_reports) output. |

### hired.alignment.diff.diff_reports(old, new)

Return a structured diff of two alignment-report dicts.

Both inputs are `AlignmentReport.model_dump()` dicts. The result has:

- `verdict_changed` / `verdict_old` / `verdict_new`
- `fit_old` / `fit_new`
- `bucket_changes`: list of `{requirement, from, to}` for requirements
  whose bucket moved (the heart of a refresh — typically UNKNOWN→known as
  Q&A resolves false negatives)
- `added` / `removed`: requirement texts present in only one version
- `clarifications_resolved`: clarifying questions in old but not new

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### hired.alignment.diff.summarize_diff(diff)

A short human-readable summary of [`diff_reports()`](_autosummary/hired.alignment.diff.html.md#hired.alignment.diff.diff_reports) output.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)


# _autosummary/hired.alignment.elicitation.html.md

# hired.alignment.elicitation

The honesty loop: rank unknowns into the most informative questions first.

This module is deterministic scaffolding around a judgment the analyst makes.
It computes which `UNKNOWN` requirements are worth asking about, in what order
(by expected information gain ≈ profile-uncertainty × requirement-criticality),
and whether the analysis has become *decision-stable* enough to stop.

See `misc/docs/DESIGN.md` §8.

### Functions

| [`info_gain`](_autosummary/hired.alignment.elicitation.html.md#hired.alignment.elicitation.info_gain)(record)                       | Expected information gain of resolving this requirement, wrt the verdict.                                                                   |
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| [`is_decision_relevant`](_autosummary/hired.alignment.elicitation.html.md#hired.alignment.elicitation.is_decision_relevant)(record)            | A requirement is worth asking about only if resolving it could move the verdict — i.e. it's not a low-value-add nice-to-have we can ignore. |
| [`is_decision_stable`](_autosummary/hired.alignment.elicitation.html.md#hired.alignment.elicitation.is_decision_stable)(records)             | True when no remaining open unknown could flip the verdict.                                                                                 |
| [`rank_clarifications`](_autosummary/hired.alignment.elicitation.html.md#hired.alignment.elicitation.rank_clarifications)(records, \*[, ...]) | Produce clarifying questions for askable records, highest info-gain first.                                                                  |
| [`should_ask`](_autosummary/hired.alignment.elicitation.html.md#hired.alignment.elicitation.should_ask)(record)                      | Whether to route this record to a clarifying question.                                                                                      |

### hired.alignment.elicitation.info_gain(record)

Expected information gain of resolving this requirement, wrt the verdict.

Heuristic: `uncertainty × criticality`. An `impact` override (1-5) scales
criticality when the analyst has a sharper view than the requirement class.

* **Return type:**
  [`float`](https://docs.python.org/3/builtins/functions.html#float)

### hired.alignment.elicitation.is_decision_relevant(record)

A requirement is worth asking about only if resolving it could move the
verdict — i.e. it’s not a low-value-add nice-to-have we can ignore.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.alignment.elicitation.is_decision_stable(records)

True when no remaining open unknown could flip the verdict.

Concretely: there are no askable (decision-relevant, open, unknown)
requirements left. This is the sharpest stop criterion from the research.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.alignment.elicitation.rank_clarifications(records, , max_questions=None, min_info_gain=0.0)

Produce clarifying questions for askable records, highest info-gain first.

The question *text* is left to the analyst; this returns the prioritized
skeleton (requirement, reason, info_gain) so the caller can fill `question`.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`Clarification`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Clarification)]

### hired.alignment.elicitation.should_ask(record)

Whether to route this record to a clarifying question.

Ask only when it’s `UNKNOWN` on an OPEN field and decision-relevant — the
“don’t assume absence from silence” rule. CONTRADICTED facts and closed-field
unknowns are real gaps, not questions.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)


# _autosummary/hired.alignment.html.md

# hired.alignment

JD-vs-candidate alignment: classify each requirement honestly into four buckets.

Public surface:

- schemas in [`hired.alignment.base`](_autosummary/hired.alignment.base.html.md#module-hired.alignment.base) ([`Requirement`](_autosummary/hired.alignment.html.md#hired.alignment.Requirement),
  [`RequirementRecord`](_autosummary/hired.alignment.html.md#hired.alignment.RequirementRecord), [`AlignmentReport`](_autosummary/hired.alignment.html.md#hired.alignment.AlignmentReport), and the enums),
- the deterministic rubric in [`hired.alignment.rubric`](_autosummary/hired.alignment.rubric.html.md#module-hired.alignment.rubric)
  ([`classify()`](_autosummary/hired.alignment.html.md#hired.alignment.classify), [`assign_bucket()`](_autosummary/hired.alignment.html.md#hired.alignment.assign_bucket), [`apply_ai_leverage()`](_autosummary/hired.alignment.html.md#hired.alignment.apply_ai_leverage)),
- the elicitation helpers in [`hired.alignment.elicitation`](_autosummary/hired.alignment.elicitation.html.md#module-hired.alignment.elicitation)
  ([`rank_clarifications()`](_autosummary/hired.alignment.html.md#hired.alignment.rank_clarifications), [`is_decision_stable()`](_autosummary/hired.alignment.html.md#hired.alignment.is_decision_stable)),
- Markdown rendering in [`hired.alignment.report`](_autosummary/hired.alignment.report.html.md#module-hired.alignment.report)
  ([`render_report_markdown()`](_autosummary/hired.alignment.html.md#hired.alignment.render_report_markdown)).

The *intelligence* (judging transfer distance, trainability, evidence) is supplied
by the `hired-align` skill (Claude as brain) or an injected LLM; this package
provides the schemas, deterministic scoring, and rendering. See
`misc/docs/DESIGN.md` §6-8.

### Functions

| [`classify`](_autosummary/hired.alignment.html.md#hired.alignment.classify)(record)                                  | Fill `gap_size` and `bucket` (and `needs_clarification`) in place.                                        |
|----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|
| [`assign_bucket`](_autosummary/hired.alignment.html.md#hired.alignment.assign_bucket)(record)                             | Assign the alignment bucket for a record, or `None` if it should be a clarifying question instead.        |
| [`apply_ai_leverage`](_autosummary/hired.alignment.html.md#hired.alignment.apply_ai_leverage)(closeability, ai_leverage, ...) | Soften a *codified* gap's closeability by the candidate's AI leverage.                                    |
| [`compute_gap_size`](_autosummary/hired.alignment.html.md#hired.alignment.compute_gap_size)(required_level, candidate_level) | Residual gap, floored at zero.                                                                            |
| [`rank_clarifications`](_autosummary/hired.alignment.html.md#hired.alignment.rank_clarifications)(records, \*[, ...])           | Produce clarifying questions for askable records, highest info-gain first.                                |
| [`is_decision_stable`](_autosummary/hired.alignment.html.md#hired.alignment.is_decision_stable)(records)                       | True when no remaining open unknown could flip the verdict.                                               |
| [`should_ask`](_autosummary/hired.alignment.html.md#hired.alignment.should_ask)(record)                                | Whether to route this record to a clarifying question.                                                    |
| [`info_gain`](_autosummary/hired.alignment.html.md#hired.alignment.info_gain)(record)                                 | Expected information gain of resolving this requirement, wrt the verdict.                                 |
| [`render_report_markdown`](_autosummary/hired.alignment.html.md#hired.alignment.render_report_markdown)(report)                    | Render the report as a Markdown string.                                                                   |
| [`diff_reports`](_autosummary/hired.alignment.html.md#hired.alignment.diff_reports)(old, new)                            | Return a structured diff of two alignment-report dicts.                                                   |
| [`summarize_diff`](_autosummary/hired.alignment.html.md#hired.alignment.summarize_diff)(diff)                              | A short human-readable summary of [`diff_reports()`](_autosummary/hired.alignment.html.md#hired.alignment.diff_reports) output. |

### Classes

| [`Requirement`](_autosummary/hired.alignment.html.md#hired.alignment.Requirement)(\*\*data)       | One atomic requirement extracted verbatim from a job description.        |
|------------------------------------------------------------------------------|--------------------------------------------------------------------------|
| [`RequirementRecord`](_autosummary/hired.alignment.html.md#hired.alignment.RequirementRecord)(\*\*data) | The analysis of one requirement against the candidate's knowledge.       |
| [`Evidence`](_autosummary/hired.alignment.html.md#hired.alignment.Evidence)(\*\*data)          | A verbatim grounding span for a match judgment.                          |
| [`AlignmentReport`](_autosummary/hired.alignment.html.md#hired.alignment.AlignmentReport)(\*\*data)   | A complete, verdict-first alignment analysis for one JD.                 |
| [`Verdict`](_autosummary/hired.alignment.html.md#hired.alignment.Verdict)(\*\*data)           |                                                                          |
| [`ScoreSummary`](_autosummary/hired.alignment.html.md#hired.alignment.ScoreSummary)(\*\*data)      |                                                                          |
| [`NextAction`](_autosummary/hired.alignment.html.md#hired.alignment.NextAction)(\*\*data)        |                                                                          |
| [`Clarification`](_autosummary/hired.alignment.html.md#hired.alignment.Clarification)(\*\*data)     | A question to ask the candidate to resolve a decision-relevant unknown.  |
| [`InterviewPrep`](_autosummary/hired.alignment.html.md#hired.alignment.InterviewPrep)(\*\*data)     |                                                                          |
| [`Bucket`](_autosummary/hired.alignment.html.md#hired.alignment.Bucket)(\*values)            | The four alignment buckets.                                              |
| [`MatchType`](_autosummary/hired.alignment.html.md#hired.alignment.MatchType)(\*values)         | How the candidate's background relates to the requirement (Axis A).      |
| [`RequirementClass`](_autosummary/hired.alignment.html.md#hired.alignment.RequirementClass)(\*values)  | How decision-critical a requirement is.                                  |
| [`SkillType`](_autosummary/hired.alignment.html.md#hired.alignment.SkillType)(\*values)         |                                                                          |
| [`Closeability`](_autosummary/hired.alignment.html.md#hired.alignment.Closeability)(\*values)      | How hard a gap is to close (Axis B), after the AI-leverage modifier.     |
| [`CloseMethod`](_autosummary/hired.alignment.html.md#hired.alignment.CloseMethod)(\*values)       |                                                                          |
| [`TimeToClose`](_autosummary/hired.alignment.html.md#hired.alignment.TimeToClose)(\*values)       |                                                                          |
| [`Transferability`](_autosummary/hired.alignment.html.md#hired.alignment.Transferability)(\*values)   |                                                                          |
| [`AILeverage`](_autosummary/hired.alignment.html.md#hired.alignment.AILeverage)(\*values)        | How much the candidate's standing AI-agent capability lowers the ramp.   |
| [`FieldCompleteness`](_autosummary/hired.alignment.html.md#hired.alignment.FieldCompleteness)(\*values) | Local closed-world flag: may a missing value be read as a real negative? |
| [`Recommendation`](_autosummary/hired.alignment.html.md#hired.alignment.Recommendation)(\*values)    |                                                                          |
| [`FitBand`](_autosummary/hired.alignment.html.md#hired.alignment.FitBand)(\*values)           |                                                                          |

### *class* hired.alignment.AILeverage(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

How much the candidate’s standing AI-agent capability lowers the ramp.

Applies to *codified / knowledge-breadth* gaps, not tacit-judgment or
enduring-aptitude gaps (those it cannot rescue).

### *class* hired.alignment.AlignmentReport(\*\*data)

Bases: `BaseModel`

A complete, verdict-first alignment analysis for one JD.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.Bucket(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

The four alignment buckets.

### *class* hired.alignment.Clarification(\*\*data)

Bases: `BaseModel`

A question to ask the candidate to resolve a decision-relevant unknown.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.CloseMethod(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.Closeability(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

How hard a gap is to close (Axis B), after the AI-leverage modifier.

### *class* hired.alignment.Evidence(\*\*data)

Bases: `BaseModel`

A verbatim grounding span for a match judgment.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.FieldCompleteness(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Local closed-world flag: may a missing value be read as a real negative?

### *class* hired.alignment.FitBand(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.InterviewPrep(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.MatchType(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

How the candidate’s background relates to the requirement (Axis A).

### *class* hired.alignment.NextAction(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.Recommendation(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.Requirement(\*\*data)

Bases: `BaseModel`

One atomic requirement extracted verbatim from a job description.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.RequirementClass(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

How decision-critical a requirement is.

### *class* hired.alignment.RequirementRecord(\*\*data)

Bases: `BaseModel`

The analysis of one requirement against the candidate’s knowledge.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.ScoreSummary(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.alignment.SkillType(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.TimeToClose(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.Transferability(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

### *class* hired.alignment.Verdict(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### hired.alignment.apply_ai_leverage(closeability, ai_leverage, , skill_type, is_tacit=False)

Soften a *codified* gap’s closeability by the candidate’s AI leverage.

Tacit/soft gaps and structurally-hard gaps are never softened — AI agents
extend *breadth of codified knowledge*, not judgment or enduring aptitude.

* **Return type:**
  [`Closeability`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Closeability)

```pycon
>>> apply_ai_leverage(Closeability.REQUIRES_EXPERIENCE, AILeverage.HIGH,
...                    skill_type=SkillType.TECHNICAL)
<Closeability.LEARNABLE: 'learnable'>
>>> apply_ai_leverage(Closeability.REQUIRES_EXPERIENCE, AILeverage.HIGH,
...                    skill_type=SkillType.SOFT_SKILL)
<Closeability.REQUIRES_EXPERIENCE: 'requires_experience'>
```

### hired.alignment.assign_bucket(record)

Assign the alignment bucket for a record, or `None` if it should be a
clarifying question instead.

Returns `None` when the requirement is `UNKNOWN` on an OPEN field — that
routes to elicitation rather than being scored as a gap (the “don’t assume
absence” rule). `UNKNOWN` on a CLOSED field is treated as a real gap.

* **Return type:**
  [`Bucket`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Bucket) | [`None`](https://docs.python.org/3/builtins/constants.html#None)

### hired.alignment.classify(record)

Fill `gap_size` and `bucket` (and `needs_clarification`) in place.

Returns the same record for convenience.

* **Return type:**
  [`RequirementRecord`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.RequirementRecord)

### hired.alignment.compute_gap_size(required_level, candidate_level)

Residual gap, floored at zero.

* **Return type:**
  [`int`](https://docs.python.org/3/builtins/functions.html#int)

### hired.alignment.diff_reports(old, new)

Return a structured diff of two alignment-report dicts.

Both inputs are `AlignmentReport.model_dump()` dicts. The result has:

- `verdict_changed` / `verdict_old` / `verdict_new`
- `fit_old` / `fit_new`
- `bucket_changes`: list of `{requirement, from, to}` for requirements
  whose bucket moved (the heart of a refresh — typically UNKNOWN→known as
  Q&A resolves false negatives)
- `added` / `removed`: requirement texts present in only one version
- `clarifications_resolved`: clarifying questions in old but not new

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### hired.alignment.info_gain(record)

Expected information gain of resolving this requirement, wrt the verdict.

Heuristic: `uncertainty × criticality`. An `impact` override (1-5) scales
criticality when the analyst has a sharper view than the requirement class.

* **Return type:**
  [`float`](https://docs.python.org/3/builtins/functions.html#float)

### hired.alignment.is_decision_stable(records)

True when no remaining open unknown could flip the verdict.

Concretely: there are no askable (decision-relevant, open, unknown)
requirements left. This is the sharpest stop criterion from the research.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.alignment.rank_clarifications(records, , max_questions=None, min_info_gain=0.0)

Produce clarifying questions for askable records, highest info-gain first.

The question *text* is left to the analyst; this returns the prioritized
skeleton (requirement, reason, info_gain) so the caller can fill `question`.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`Clarification`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Clarification)]

### hired.alignment.render_report_markdown(report)

Render the report as a Markdown string.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### hired.alignment.should_ask(record)

Whether to route this record to a clarifying question.

Ask only when it’s `UNKNOWN` on an OPEN field and decision-relevant — the
“don’t assume absence from silence” rule. CONTRADICTED facts and closed-field
unknowns are real gaps, not questions.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.alignment.summarize_diff(diff)

A short human-readable summary of [`diff_reports()`](_autosummary/hired.alignment.html.md#hired.alignment.diff_reports) output.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### Modules

| [`base`](_autosummary/hired.alignment.base.html.md#module-hired.alignment.base)               | Schemas for JD-vs-candidate alignment analysis.                                                                              |
|-------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| [`diff`](_autosummary/hired.alignment.diff.html.md#module-hired.alignment.diff)               | Deterministic diff between two alignment reports.                                                                            |
| [`elicitation`](_autosummary/hired.alignment.elicitation.html.md#module-hired.alignment.elicitation) | The honesty loop: rank unknowns into the most informative questions first.                                                   |
| [`report`](_autosummary/hired.alignment.report.html.md#module-hired.alignment.report)           | Render an [`AlignmentReport`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.AlignmentReport) to Markdown. |
| [`rubric`](_autosummary/hired.alignment.rubric.html.md#module-hired.alignment.rubric)           | Deterministic bucket assignment — the two-axis rubric in code.                                                               |


# _autosummary/hired.alignment.report.html.md

# hired.alignment.report

Render an [`AlignmentReport`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.AlignmentReport) to Markdown.

Verdict-first (BLUF), evidence-quoted, banded — deliberately *not* a single
false-precision percentage. The four buckets are grouped so the reader sees, in
order: what’s strong, what transfers, what’s learnable (with the AI-leverage
note), what’s genuinely hard, and what we still need to ask.

See `misc/docs/DESIGN.md` §6, and the research in
`misc/docs/research/jd-candidate-matching.md`.

### Functions

| [`render_report_markdown`](_autosummary/hired.alignment.report.html.md#hired.alignment.report.render_report_markdown)(report)   | Render the report as a Markdown string.   |
|-----------------------------------------------------------------------------------|-------------------------------------------|

### hired.alignment.report.render_report_markdown(report)

Render the report as a Markdown string.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)


# _autosummary/hired.alignment.rubric.html.md

# hired.alignment.rubric

Deterministic bucket assignment — the two-axis rubric in code.

The *judgment* (transfer distance, trainability, evidence) is supplied by the
analyst (Claude or an injected LLM). This module turns those judgments into a
[`Bucket`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Bucket) deterministically, so the classification is
auditable and reproducible. It also applies the **AI-leverage modifier**: a
candidate who works with armies of AI agents closes *codified / knowledge-breadth*
gaps faster — but not *tacit-judgment* or *enduring-aptitude* gaps.

See `misc/docs/DESIGN.md` §7.

### Functions

| [`apply_ai_leverage`](_autosummary/hired.alignment.rubric.html.md#hired.alignment.rubric.apply_ai_leverage)(closeability, ai_leverage, ...)   | Soften a *codified* gap's closeability by the candidate's AI leverage.                             |
|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------|
| [`assign_bucket`](_autosummary/hired.alignment.rubric.html.md#hired.alignment.rubric.assign_bucket)(record)                               | Assign the alignment bucket for a record, or `None` if it should be a clarifying question instead. |
| [`classify`](_autosummary/hired.alignment.rubric.html.md#hired.alignment.rubric.classify)(record)                                    | Fill `gap_size` and `bucket` (and `needs_clarification`) in place.                                 |
| [`compute_gap_size`](_autosummary/hired.alignment.rubric.html.md#hired.alignment.rubric.compute_gap_size)(required_level, candidate_level)   | Residual gap, floored at zero.                                                                     |

### hired.alignment.rubric.apply_ai_leverage(closeability, ai_leverage, , skill_type, is_tacit=False)

Soften a *codified* gap’s closeability by the candidate’s AI leverage.

Tacit/soft gaps and structurally-hard gaps are never softened — AI agents
extend *breadth of codified knowledge*, not judgment or enduring aptitude.

* **Return type:**
  [`Closeability`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Closeability)

```pycon
>>> apply_ai_leverage(Closeability.REQUIRES_EXPERIENCE, AILeverage.HIGH,
...                    skill_type=SkillType.TECHNICAL)
<Closeability.LEARNABLE: 'learnable'>
>>> apply_ai_leverage(Closeability.REQUIRES_EXPERIENCE, AILeverage.HIGH,
...                    skill_type=SkillType.SOFT_SKILL)
<Closeability.REQUIRES_EXPERIENCE: 'requires_experience'>
```

### hired.alignment.rubric.assign_bucket(record)

Assign the alignment bucket for a record, or `None` if it should be a
clarifying question instead.

Returns `None` when the requirement is `UNKNOWN` on an OPEN field — that
routes to elicitation rather than being scored as a gap (the “don’t assume
absence” rule). `UNKNOWN` on a CLOSED field is treated as a real gap.

* **Return type:**
  [`Bucket`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.Bucket) | [`None`](https://docs.python.org/3/builtins/constants.html#None)

### hired.alignment.rubric.classify(record)

Fill `gap_size` and `bucket` (and `needs_clarification`) in place.

Returns the same record for convenience.

* **Return type:**
  [`RequirementRecord`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.RequirementRecord)

### hired.alignment.rubric.compute_gap_size(required_level, candidate_level)

Residual gap, floored at zero.

* **Return type:**
  [`int`](https://docs.python.org/3/builtins/functions.html#int)


# _autosummary/hired.ats_checker.html.md

# hired.ats_checker

ATS (Applicant Tracking System) compatibility checker.

Analyze resumes to ensure they’re compatible with automated screening systems.

### Functions

| [`check_resume_ats`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.check_resume_ats)(resume_content[, job])   | Quick utility to check resume ATS compatibility.   |
|--------------------------------------------------------------------------------------------|----------------------------------------------------|

### Classes

| [`ATSChecker`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSChecker)()                                | Check resume for ATS compatibility.    |
|----------------------------------------------------------------------------------------------|----------------------------------------|
| [`ATSIssue`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSIssue)(category, title, description, ...) | Represents an ATS compatibility issue. |
| [`ATSReport`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSReport)(overall_score[, issues, ...])     | Report from ATS compatibility check.   |

### *class* hired.ats_checker.ATSChecker

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Check resume for ATS compatibility.

### Examples

```pycon
>>> from hired.ats_checker import ATSChecker
>>>
>>> checker = ATSChecker()
>>> report = checker.check_resume(resume_dict)
>>> print(report.get_summary())
>>>
>>> # Check against specific job
>>> report = checker.check_resume(resume_dict, job_result)
```

#### check_resume(resume_content, job=None)

Check resume for ATS compatibility.

* **Parameters:**
  * **resume_content** ([`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Resume content as dictionary (JSON Resume format)
  * **job** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Optional JobResult to check keyword matching
* **Return type:**
  [`ATSReport`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSReport)
* **Returns:**
  ATSReport with compatibility score and issues

### *class* hired.ats_checker.ATSIssue(category, title, description, suggestion)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Represents an ATS compatibility issue.

### *class* hired.ats_checker.ATSReport(overall_score, issues=<factory>, keyword_match_score=0.0, matched_keywords=<factory>, missing_keywords=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Report from ATS compatibility check.

#### get_critical_issues()

Get critical issues.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`ATSIssue`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSIssue)]

#### get_issues_by_category(category)

Get issues filtered by category.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`ATSIssue`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSIssue)]

#### get_summary()

Get human-readable summary.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### get_warnings()

Get warnings.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`ATSIssue`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSIssue)]

#### to_dict()

Convert to dictionary.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### hired.ats_checker.check_resume_ats(resume_content, job=None)

Quick utility to check resume ATS compatibility.

* **Parameters:**
  * **resume_content** ([`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Resume content as dictionary (JSON Resume format)
  * **job** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Optional JobResult for keyword matching
* **Return type:**
  [`ATSReport`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSReport)
* **Returns:**
  ATSReport

### Examples

```pycon
>>> from hired import mk_content_for_resume
>>> from hired.ats_checker import check_resume_ats
>>>
>>> resume = mk_content_for_resume(candidate_info, job_info)
>>> report = check_resume_ats(resume.model_dump(), job_result)
>>> print(report.get_summary())
```


# _autosummary/hired.base.html.md

# hired.base

Core data models and protocols for the hired package.

Define:

- RenderingConfig: Configuration for rendering pipeline
- ContentSource: Protocol for data sources (candidate/job info)
- AIAgent: Protocol for content generation agents
- Renderer: Protocol for resume renderers
- ResumeSchemaExtended: Extended version of ResumeSchema that allows extra fields

### Functions

| [`get_renderer_registry`](_autosummary/hired.base.html.md#hired.base.get_renderer_registry)()        | Get the global renderer registry.           |
|---------------------------------------------------------------------------------|---------------------------------------------|
| [`register_renderer`](_autosummary/hired.base.html.md#hired.base.register_renderer)(format_name) | Decorator for registering renderer classes. |

### Classes

| [`AIAgent`](_autosummary/hired.base.html.md#hired.base.AIAgent)(\*args, \*\*kwargs)                       | Protocol for AI agents that generate resume content.                           |
|----------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------|
| [`ContentSource`](_autosummary/hired.base.html.md#hired.base.ContentSource)(\*args, \*\*kwargs)                 | Protocol for sources that provide candidate or job information.                |
| [`Renderer`](_autosummary/hired.base.html.md#hired.base.Renderer)(\*args, \*\*kwargs)                      | Protocol for resume renderers.                                                 |
| [`RendererRegistry`](_autosummary/hired.base.html.md#hired.base.RendererRegistry)()                                | Registry for managing multiple renderer implementations.                       |
| [`RenderingConfig`](_autosummary/hired.base.html.md#hired.base.RenderingConfig)([format, theme, custom_css, ...]) | Configuration for resume rendering.                                            |
| [`ResumeSchemaExtended`](_autosummary/hired.base.html.md#hired.base.ResumeSchemaExtended)(\*\*data)                    | Extended version of ResumeSchema that allows extra fields for custom sections. |

### *class* hired.base.AIAgent(\*args, \*\*kwargs)

Bases: [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol)

Protocol for AI agents that generate resume content.

### *class* hired.base.ContentSource(\*args, \*\*kwargs)

Bases: [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol)

Protocol for sources that provide candidate or job information.

### *class* hired.base.Renderer(\*args, \*\*kwargs)

Bases: [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol)

Protocol for resume renderers.

### *class* hired.base.RendererRegistry

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Registry for managing multiple renderer implementations.

#### get_renderer(format_name)

Get a renderer instance for the specified format.

* **Return type:**
  [`Renderer`](_autosummary/hired.base.html.md#hired.base.Renderer)

#### is_registered(format_name)

Check if a format is registered.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

#### list_formats()

List all registered format names.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### register(format_name, renderer_class)

Register a renderer class for a specific format.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.base.RenderingConfig(format='pdf', theme='default', custom_css=None, custom_template=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Configuration for resume rendering.

### *class* hired.base.ResumeSchemaExtended(\*\*data)

Bases: [`ResumeSchema`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.ResumeSchema)

Extended version of ResumeSchema that allows extra fields for custom sections.

This class inherits all the validation and structure from ResumeSchema
but allows additional fields to be stored for custom sections.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### hired.base.get_renderer_registry()

Get the global renderer registry.

* **Return type:**
  [`RendererRegistry`](_autosummary/hired.base.html.md#hired.base.RendererRegistry)

### hired.base.register_renderer(format_name)

Decorator for registering renderer classes.

* **Return type:**
  [`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[[`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)(`_RendererClass`, bound= [`type`](https://docs.python.org/3/builtins/functions.html#type)[[`Renderer`](_autosummary/hired.base.html.md#hired.base.Renderer)])], [`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)(`_RendererClass`, bound= [`type`](https://docs.python.org/3/builtins/functions.html#type)[[`Renderer`](_autosummary/hired.base.html.md#hired.base.Renderer)])]


# _autosummary/hired.candidate.base.html.md

# hired.candidate.base

Open-world, provenance-first schemas for accumulated candidate knowledge.

The governing principle (see `misc/docs/DESIGN.md` §5): the **absence** of a
fact is never a negative claim. Only an explicit fact whose `match_state` is
`CONTRADICTED` asserts that the candidate lacks something. Silence is
`UNKNOWN` — a prompt to *ask*, not a gap.

Every [`Fact`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Fact) carries [`Provenance`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Provenance). When a provenance `quote` is
drawn from a text source it MUST be a verbatim substring of that source — an
anti-hallucination invariant enforced at extraction time.

### Functions

| [`slug`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.slug)(text)   | A filesystem-safe, extension-less key from an arbitrary label.   |
|---------------------------------------------------------------|------------------------------------------------------------------|

### Classes

| [`ConfidenceLevel`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.ConfidenceLevel)(\*values)   | Calibrated confidence in a claim (qualitative, not a raw probability).   |
|------------------------------------------------------------------------------|--------------------------------------------------------------------------|
| [`Fact`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Fact)(\*\*data)              | One atomic claim about a candidate.                                      |
| [`FactCategory`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.FactCategory)(\*values)      | Coarse category for retrieval and synopsis grouping.                     |
| [`FactStatus`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.FactStatus)(\*values)        | Whether a fact is current or has been superseded by a newer one.         |
| [`MatchState`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.MatchState)(\*values)        | Three-valued epistemic state — the core of the honesty contract.         |
| [`Provenance`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Provenance)(\*\*data)        | Where a fact came from, with an optional verbatim supporting quote.      |
| [`QAEntry`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.QAEntry)(\*\*data)           | One clarifying question asked of the candidate and their answer.         |
| [`SourceKind`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.SourceKind)(\*values)        | Where a piece of provenance came from.                                   |

### *class* hired.candidate.base.ConfidenceLevel(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Calibrated confidence in a claim (qualitative, not a raw probability).

### *class* hired.candidate.base.Fact(\*\*data)

Bases: `BaseModel`

One atomic claim about a candidate.

Atomicity matters: a fact states a single thing so it can be confirmed,
superseded, or cited independently.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.candidate.base.FactCategory(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Coarse category for retrieval and synopsis grouping.

### *class* hired.candidate.base.FactStatus(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Whether a fact is current or has been superseded by a newer one.

### *class* hired.candidate.base.MatchState(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Three-valued epistemic state — the core of the honesty contract.

`UNKNOWN` is distinct from `CONTRADICTED`: we have not yet looked, so we
must *ask* rather than assume absence.

### *class* hired.candidate.base.Provenance(\*\*data)

Bases: `BaseModel`

Where a fact came from, with an optional verbatim supporting quote.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.candidate.base.QAEntry(\*\*data)

Bases: `BaseModel`

One clarifying question asked of the candidate and their answer.

Q&A is append-only history; the distilled, updatable projection lives in
[`Fact`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Fact) records (linked via `derived_fact_ids`).

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.candidate.base.SourceKind(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Where a piece of provenance came from.

### hired.candidate.base.slug(text)

A filesystem-safe, extension-less key from an arbitrary label.

Used to derive stable store keys from human labels (company names, subjects,
briefing titles) so callers pass natural text and the store stays tidy.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> slug('Socure, Inc.')
'socure-inc'
>>> slug('KYC / AML primer')
'kyc-aml-primer'
```


# _autosummary/hired.candidate.html.md

# hired.candidate

Candidate knowledge domain: accumulate open-world facts about a candidate.

The public facade is [`CandidateKnowledgeBase`](_autosummary/hired.candidate.html.md#hired.candidate.CandidateKnowledgeBase). Schemas ([`Fact`](_autosummary/hired.candidate.html.md#hired.candidate.Fact),
[`QAEntry`](_autosummary/hired.candidate.html.md#hired.candidate.QAEntry), [`Provenance`](_autosummary/hired.candidate.html.md#hired.candidate.Provenance), and the enums) live in
[`hired.candidate.base`](_autosummary/hired.candidate.base.html.md#module-hired.candidate.base); document/Q&A ingest in [`hired.candidate.ingest`](_autosummary/hired.candidate.ingest.html.md#module-hired.candidate.ingest).

See `misc/docs/DESIGN.md` §5.

### Functions

| [`needs_refresh`](_autosummary/hired.candidate.html.md#hired.candidate.needs_refresh)(kb)                                 | True when there is uningested source/Q&A material — a refresh is warranted.                           |
|----------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------|
| [`refresh`](_autosummary/hired.candidate.html.md#hired.candidate.refresh)(kb[, mode, ingest_fn, apply])             | Refresh `info` from changed sources + undistilled Q&A.                                                |
| [`slug`](_autosummary/hired.candidate.html.md#hired.candidate.slug)(text)                                        | A filesystem-safe, extension-less key from an arbitrary label.                                        |
| [`ingest_facts`](_autosummary/hired.candidate.html.md#hired.candidate.ingest_facts)(kb, records, \*, source_kind[, ...]) | Validate, quote-check, and persist fact records; return persisted ids.                                |
| [`fact_from_record`](_autosummary/hired.candidate.html.md#hired.candidate.fact_from_record)(record, \*, source_kind[, ...])  | Build a (not-yet-persisted) [`Fact`](_autosummary/hired.candidate.html.md#hired.candidate.Fact) from a record dict. |
| [`verify_quote`](_autosummary/hired.candidate.html.md#hired.candidate.verify_quote)(quote, source_text)                  | True if `quote` is a verbatim substring of `source_text`.                                             |

### Classes

| [`CandidateKnowledgeBase`](_autosummary/hired.candidate.html.md#hired.candidate.CandidateKnowledgeBase)([user, store])        | Accumulated, open-world knowledge about a single candidate (user-level).                 |
|-----------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
| [`JDWorkspace`](_autosummary/hired.candidate.html.md#hired.candidate.JDWorkspace)(kb, jd_id, \*[, store])          | Reports, company research, interview-prep briefings, and parsed jobs for one engagement. |
| [`TopicDossier`](_autosummary/hired.candidate.html.md#hired.candidate.TopicDossier)(base_dir, \*[, name])           | One subject's dossier: an `overview.md` plus optional attached files.                    |
| [`RefreshState`](_autosummary/hired.candidate.html.md#hired.candidate.RefreshState)(\*\*data)                       | The candidate-info refresh ledger (persisted to `user/info/state.json`).                 |
| [`SourceDigest`](_autosummary/hired.candidate.html.md#hired.candidate.SourceDigest)(\*\*data)                       | What we know about one raw source for change detection + provenance.                     |
| [`RefreshItem`](_autosummary/hired.candidate.html.md#hired.candidate.RefreshItem)(kind, key, content)              | One unit of pending work for a refresh: a changed source or an undistilled Q&A.          |
| [`RefreshProposal`](_autosummary/hired.candidate.html.md#hired.candidate.RefreshProposal)(kind, key, records)          | Proposed fact records for one item (returned when `apply=False`).                        |
| [`RefreshReport`](_autosummary/hired.candidate.html.md#hired.candidate.RefreshReport)(mode, applied[, pending, ...]) | Outcome (or preview) of a refresh.                                                       |
| [`Fact`](_autosummary/hired.candidate.html.md#hired.candidate.Fact)(\*\*data)                               | One atomic claim about a candidate.                                                      |
| [`QAEntry`](_autosummary/hired.candidate.html.md#hired.candidate.QAEntry)(\*\*data)                            | One clarifying question asked of the candidate and their answer.                         |
| [`Provenance`](_autosummary/hired.candidate.html.md#hired.candidate.Provenance)(\*\*data)                         | Where a fact came from, with an optional verbatim supporting quote.                      |
| [`FactCategory`](_autosummary/hired.candidate.html.md#hired.candidate.FactCategory)(\*values)                       | Coarse category for retrieval and synopsis grouping.                                     |
| [`FactStatus`](_autosummary/hired.candidate.html.md#hired.candidate.FactStatus)(\*values)                         | Whether a fact is current or has been superseded by a newer one.                         |
| [`SourceKind`](_autosummary/hired.candidate.html.md#hired.candidate.SourceKind)(\*values)                         | Where a piece of provenance came from.                                                   |
| [`ConfidenceLevel`](_autosummary/hired.candidate.html.md#hired.candidate.ConfidenceLevel)(\*values)                    | Calibrated confidence in a claim (qualitative, not a raw probability).                   |
| [`MatchState`](_autosummary/hired.candidate.html.md#hired.candidate.MatchState)(\*values)                         | Three-valued epistemic state — the core of the honesty contract.                         |

### *class* hired.candidate.CandidateKnowledgeBase(user='me', , store=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Accumulated, open-world knowledge about a single candidate (user-level).

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> kb = CandidateKnowledgeBase()                 # default candidate "me"
>>> from hired.candidate.base import Fact, FactCategory
>>> _ = kb.add_fact(Fact(statement='Built ML pipelines in Python',
...                       category=FactCategory.SKILL, tags=['python', 'ml']))
>>> [f.statement for f in kb.facts(category=FactCategory.SKILL)]
['Built ML pipelines in Python']
>>> [f.statement for f in kb.facts(tags=['ml'])]
['Built ML pipelines in Python']
```

#### add_fact(fact)

Persist a fact, returning its id.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### add_note(subject, text=None, , files=None)

Record volunteered info about a subject into its dossier.

`text` is appended to the dossier’s `overview.md`; `files` (a
`{name: bytes}` mapping) are attached as detail/media. Returns the
dossier. This is the “by the way, I also did X” entry point — a single
sentence or a whole folder both land here.

* **Return type:**
  [`TopicDossier`](_autosummary/hired.candidate.topics.html.md#hired.candidate.topics.TopicDossier)

#### add_source(src, , name=None)

Store a raw source (file path or bytes) and record its content digest.

Returns the source key (its name in the raw store). The digest (in
`state.json`) lets a later refresh detect new/changed sources without
re-reading everything. Facts extracted from a source cite it by this key.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### facts(, category=None, tags=None, status=FactStatus.ASSERTED, include_negations=True)

Iterate facts, optionally filtered by category/tags/status.

By default only `ASSERTED` facts are returned (superseded ones are
hidden). `tags` matches facts containing *any* of the given tags.

* **Return type:**
  [`Iterator`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator)[[`Fact`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Fact)]

#### jd(jd_id, , company=None, label=None)

Get-or-create the workspace for an engagement (1+ JDs of one company).

`company` / `label` are recorded in the engagement’s `meta` when given.

* **Return type:**
  [`JDWorkspace`](_autosummary/hired.candidate.workspace.html.md#hired.candidate.workspace.JDWorkspace)

#### jds()

Ids of all engagements for this candidate.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### needs_refresh()

True when uningested source/Q&A material exists (refresh warranted).

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

#### pending_qa()

Q&A entries not yet distilled into facts.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`QAEntry`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.QAEntry)]

#### pending_sources()

Raw sources new, changed, or not yet distilled into facts.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### record_qa(entry, , derived_facts=None)

Append a clarifying Q&A exchange; optionally distill it into facts.

When `derived_facts` (atomic fact records extracted from the answer) are
given, they are ingested with `SourceKind.QA` provenance (`source_id`
= the Q&A id, quotes verified against the answer) and back-linked via the
entry’s `derived_fact_ids` — so a Q&A answer becomes reusable,
discoverable knowledge rather than being buried in the history.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### refresh(mode='soft', , ingest_fn=None, apply=True)

Refresh `info` from changed sources + undistilled Q&A.

`ingest_fn(item)` supplies extraction (intelligence is external); with
`apply=False` the result is a non-destructive preview. See
[`hired.candidate.refresh`](_autosummary/hired.candidate.html.md#hired.candidate.refresh).

* **Return type:**
  [`RefreshReport`](_autosummary/hired.candidate.html.md#hired.candidate.RefreshReport)

#### regenerate_synopsis()

Rebuild and persist a human-readable synopsis from current facts.

This is a *projection* — always derived from the fact store, never
hand-edited — so it can be regenerated at any time without loss.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### save_upload(name, data)

Store a raw uploaded document by filename (see [`add_source()`](_autosummary/hired.candidate.html.md#hired.candidate.CandidateKnowledgeBase.add_source)).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### sources()

Keys of all raw sources the candidate has provided.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### supersede(old_fact_id, new_fact)

Replace `old_fact_id` with `new_fact` (invalidate, don’t delete).

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### *property* synopsis *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

The last persisted synopsis, regenerating it if absent.

#### topic(name)

Get-or-create the dossier for a subject (overview + optional files).

* **Return type:**
  [`TopicDossier`](_autosummary/hired.candidate.topics.html.md#hired.candidate.topics.TopicDossier)

#### topics()

Slugs of all topic dossiers.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### *class* hired.candidate.ConfidenceLevel(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Calibrated confidence in a claim (qualitative, not a raw probability).

### *class* hired.candidate.Fact(\*\*data)

Bases: `BaseModel`

One atomic claim about a candidate.

Atomicity matters: a fact states a single thing so it can be confirmed,
superseded, or cited independently.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.candidate.FactCategory(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Coarse category for retrieval and synopsis grouping.

### *class* hired.candidate.FactStatus(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Whether a fact is current or has been superseded by a newer one.

### *class* hired.candidate.JDWorkspace(kb, jd_id, , store=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Reports, company research, interview-prep briefings, and parsed jobs for one engagement.

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> from hired.candidate import CandidateKnowledgeBase
>>> kb = CandidateKnowledgeBase()
>>> ws = kb.jd('acme', company='Acme, Inc.', label='Acme roles')
>>> ws.save_report('staff-ds', {'verdict': {'recommendation': 'apply'}})
>>> ws.get_report('staff-ds')['verdict']['recommendation']
'apply'
>>> ws.meta['company']
'Acme, Inc.'
```

#### report_versions(job_id)

Keys of archived prior versions of a job’s report (chronological).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### save_briefing(key, data)

Persist an interview-prep research briefing (keyed by subject/job).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### save_company_report(company, data)

Persist a company/people research report (keyed by company name).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### save_report(job_id, data, , archive=True)

Persist the current alignment report, archiving the prior one first.

Archiving (on by default) snapshots any existing report into
`report_history` so the alignment-review agent can diff versions.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.candidate.MatchState(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Three-valued epistemic state — the core of the honesty contract.

`UNKNOWN` is distinct from `CONTRADICTED`: we have not yet looked, so we
must *ask* rather than assume absence.

### *class* hired.candidate.Provenance(\*\*data)

Bases: `BaseModel`

Where a fact came from, with an optional verbatim supporting quote.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.candidate.QAEntry(\*\*data)

Bases: `BaseModel`

One clarifying question asked of the candidate and their answer.

Q&A is append-only history; the distilled, updatable projection lives in
[`Fact`](_autosummary/hired.candidate.html.md#hired.candidate.Fact) records (linked via `derived_fact_ids`).

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.candidate.RefreshItem(kind, key, content)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

One unit of pending work for a refresh: a changed source or an undistilled Q&A.

### *class* hired.candidate.RefreshProposal(kind, key, records)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Proposed fact records for one item (returned when `apply=False`).

### *class* hired.candidate.RefreshReport(mode, applied, pending=<factory>, proposals=<factory>, added_fact_ids=<factory>, superseded_fact_ids=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Outcome (or preview) of a refresh.

### *class* hired.candidate.RefreshState(\*\*data)

Bases: `BaseModel`

The candidate-info refresh ledger (persisted to `user/info/state.json`).

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.candidate.SourceDigest(\*\*data)

Bases: `BaseModel`

What we know about one raw source for change detection + provenance.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.candidate.SourceKind(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Where a piece of provenance came from.

### *class* hired.candidate.TopicDossier(base_dir, , name=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

One subject’s dossier: an `overview.md` plus optional attached files.

```pycon
>>> import tempfile, os
>>> d = TopicDossier(os.path.join(tempfile.mkdtemp(), 'patents'), name='Patents')
>>> d.add_note('Holds 3 US patents on anomaly detection.')
>>> d.overview.splitlines()[0]
'# Patents'
>>> d.add_file('cert.txt', b'patent cert')
>>> d.files()
['cert.txt']
>>> d.get_file('cert.txt')
b'patent cert'
```

#### add_file(filename, data)

Attach a detail file / media blob to the dossier.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### add_note(text)

Append a note to the overview (creating it, titled, if absent).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### exists()

True once the dossier has an overview or any attached file.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

#### files()

Names of attached detail files.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### *property* overview *: [str](https://docs.python.org/3/builtins/stdtypes.html#str) | [None](https://docs.python.org/3/builtins/constants.html#None)*

The dossier’s overview markdown (the entry point), or `None`.

### hired.candidate.fact_from_record(record, , source_kind, source_id='', subject='me')

Build a (not-yet-persisted) [`Fact`](_autosummary/hired.candidate.html.md#hired.candidate.Fact) from a record dict.

* **Return type:**
  [`Fact`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Fact)

### hired.candidate.ingest_facts(kb, records, , source_kind, source_id='', source_text=None, drop_unverified_quotes=True)

Validate, quote-check, and persist fact records; return persisted ids.

When `source_text` is given, each record’s `quote` is checked to be a
verbatim substring. Unverified quotes are dropped (the fact is still kept,
but without the spurious quote) unless `drop_unverified_quotes` is False,
in which case a `ValueError` is raised — useful for strict pipelines.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### hired.candidate.needs_refresh(kb)

True when there is uningested source/Q&A material — a refresh is warranted.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.candidate.refresh(kb, mode='soft', , ingest_fn=None, apply=True)

Refresh `info` from changed sources + undistilled Q&A. See module docstring.

`ingest_fn(item: RefreshItem) -> list[dict]` supplies the extraction
intelligence (records are the usual `{"statement", "category", "quote", …}`
dicts). With `ingest_fn=None` the report just lists the pending items (the
caller does extraction). With `apply=False` the records are returned as
proposals and nothing is written.

* **Return type:**
  [`RefreshReport`](_autosummary/hired.candidate.html.md#hired.candidate.RefreshReport)

### hired.candidate.slug(text)

A filesystem-safe, extension-less key from an arbitrary label.

Used to derive stable store keys from human labels (company names, subjects,
briefing titles) so callers pass natural text and the store stays tidy.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> slug('Socure, Inc.')
'socure-inc'
>>> slug('KYC / AML primer')
'kyc-aml-primer'
```

### hired.candidate.verify_quote(quote, source_text)

True if `quote` is a verbatim substring of `source_text`.

A `None` quote (no quote claimed) always verifies. When no source text is
available to check against, we cannot disprove it, so it verifies too — the
invariant only bites when we *can* check.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### Modules

| [`base`](_autosummary/hired.candidate.base.html.md#module-hired.candidate.base)                     | Open-world, provenance-first schemas for accumulated candidate knowledge.           |
|-------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
| [`ingest`](_autosummary/hired.candidate.ingest.html.md#module-hired.candidate.ingest)                 | Turn extracted atomic-fact records into persisted, provenance-bearing facts.        |
| [`knowledge_base`](_autosummary/hired.candidate.knowledge_base.html.md#module-hired.candidate.knowledge_base) | The candidate knowledge base: a facade over the user-level store.                   |
| [`state`](_autosummary/hired.candidate.state.html.md#module-hired.candidate.state)                   | Refresh bookkeeping: per-source content digests + last-refresh timestamps.          |
| [`topics`](_autosummary/hired.candidate.topics.html.md#module-hired.candidate.topics)                 | Topic dossiers — "a little, or a whole lot" about any subject the candidate shares. |
| [`workspace`](_autosummary/hired.candidate.workspace.html.md#module-hired.candidate.workspace)           | The per-engagement facade: alignment reports, company research, interview prep.     |


# _autosummary/hired.candidate.ingest.html.md

# hired.candidate.ingest

Turn extracted atomic-fact records into persisted, provenance-bearing facts.

The *intelligence* of extraction (reading a CV/bio/publication and proposing
atomic claims) is supplied externally — by the `hired-profile-ingest` subagent
in interactive use, or an injected LLM in autonomous use. This module is the
deterministic glue: it validates those proposals into `Fact` objects,
enforces the provenance-quote invariant, and persists them.

A *record* is a lightweight dict:

```text
{"statement": "...", "category": "skill", "tags": ["python"],
 "confidence": "high", "quote": "...", "locator": "experience[1]",
 "is_negation": false}
```

### Functions

| [`fact_from_record`](_autosummary/hired.candidate.ingest.html.md#hired.candidate.ingest.fact_from_record)(record, \*, source_kind[, ...])   | Build a (not-yet-persisted) `Fact` from a record dict.                 |
|-----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------|
| [`ingest_facts`](_autosummary/hired.candidate.ingest.html.md#hired.candidate.ingest.ingest_facts)(kb, records, \*, source_kind[, ...])  | Validate, quote-check, and persist fact records; return persisted ids. |
| [`verify_quote`](_autosummary/hired.candidate.ingest.html.md#hired.candidate.ingest.verify_quote)(quote, source_text)                   | True if `quote` is a verbatim substring of `source_text`.              |

### hired.candidate.ingest.fact_from_record(record, , source_kind, source_id='', subject='me')

Build a (not-yet-persisted) `Fact` from a record dict.

* **Return type:**
  [`Fact`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Fact)

### hired.candidate.ingest.ingest_facts(kb, records, , source_kind, source_id='', source_text=None, drop_unverified_quotes=True)

Validate, quote-check, and persist fact records; return persisted ids.

When `source_text` is given, each record’s `quote` is checked to be a
verbatim substring. Unverified quotes are dropped (the fact is still kept,
but without the spurious quote) unless `drop_unverified_quotes` is False,
in which case a `ValueError` is raised — useful for strict pipelines.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### hired.candidate.ingest.verify_quote(quote, source_text)

True if `quote` is a verbatim substring of `source_text`.

A `None` quote (no quote claimed) always verifies. When no source text is
available to check against, we cannot disprove it, so it verifies too — the
invariant only bites when we *can* check.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)


# _autosummary/hired.candidate.knowledge_base.html.md

# hired.candidate.knowledge_base

The candidate knowledge base: a facade over the user-level store.

[`CandidateKnowledgeBase`](_autosummary/hired.candidate.knowledge_base.html.md#hired.candidate.knowledge_base.CandidateKnowledgeBase) is the domain-driven entry point for accumulating
and querying knowledge about one candidate — *what is true about them*, reusable
across every job application. It wraps the [`UserStore`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.UserStore)
with validated, intention-revealing methods (`add_fact`, `facts`, `record_qa`,
`save_upload`, …) and keeps a regenerated, human-readable `synopsis()`
projection of the fact store for fast context loading.

Work tied to a specific company’s role(s) — alignment reports, company research,
interview prep — does **not** live here; it lives in a per-engagement
[`JDWorkspace`](_autosummary/hired.candidate.workspace.html.md#hired.candidate.workspace.JDWorkspace), reached via `jd()`.

### Classes

| [`CandidateKnowledgeBase`](_autosummary/hired.candidate.knowledge_base.html.md#hired.candidate.knowledge_base.CandidateKnowledgeBase)([user, store])   | Accumulated, open-world knowledge about a single candidate (user-level).   |
|------------------------------------------------------------------------------------------|----------------------------------------------------------------------------|

### *class* hired.candidate.knowledge_base.CandidateKnowledgeBase(user='me', , store=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Accumulated, open-world knowledge about a single candidate (user-level).

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> kb = CandidateKnowledgeBase()                 # default candidate "me"
>>> from hired.candidate.base import Fact, FactCategory
>>> _ = kb.add_fact(Fact(statement='Built ML pipelines in Python',
...                       category=FactCategory.SKILL, tags=['python', 'ml']))
>>> [f.statement for f in kb.facts(category=FactCategory.SKILL)]
['Built ML pipelines in Python']
>>> [f.statement for f in kb.facts(tags=['ml'])]
['Built ML pipelines in Python']
```

#### add_fact(fact)

Persist a fact, returning its id.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### add_note(subject, text=None, , files=None)

Record volunteered info about a subject into its dossier.

`text` is appended to the dossier’s `overview.md`; `files` (a
`{name: bytes}` mapping) are attached as detail/media. Returns the
dossier. This is the “by the way, I also did X” entry point — a single
sentence or a whole folder both land here.

* **Return type:**
  [`TopicDossier`](_autosummary/hired.candidate.topics.html.md#hired.candidate.topics.TopicDossier)

#### add_source(src, , name=None)

Store a raw source (file path or bytes) and record its content digest.

Returns the source key (its name in the raw store). The digest (in
`state.json`) lets a later refresh detect new/changed sources without
re-reading everything. Facts extracted from a source cite it by this key.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### facts(, category=None, tags=None, status=FactStatus.ASSERTED, include_negations=True)

Iterate facts, optionally filtered by category/tags/status.

By default only `ASSERTED` facts are returned (superseded ones are
hidden). `tags` matches facts containing *any* of the given tags.

* **Return type:**
  [`Iterator`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator)[[`Fact`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Fact)]

#### jd(jd_id, , company=None, label=None)

Get-or-create the workspace for an engagement (1+ JDs of one company).

`company` / `label` are recorded in the engagement’s `meta` when given.

* **Return type:**
  [`JDWorkspace`](_autosummary/hired.candidate.workspace.html.md#hired.candidate.workspace.JDWorkspace)

#### jds()

Ids of all engagements for this candidate.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### needs_refresh()

True when uningested source/Q&A material exists (refresh warranted).

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

#### pending_qa()

Q&A entries not yet distilled into facts.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`QAEntry`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.QAEntry)]

#### pending_sources()

Raw sources new, changed, or not yet distilled into facts.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### record_qa(entry, , derived_facts=None)

Append a clarifying Q&A exchange; optionally distill it into facts.

When `derived_facts` (atomic fact records extracted from the answer) are
given, they are ingested with `SourceKind.QA` provenance (`source_id`
= the Q&A id, quotes verified against the answer) and back-linked via the
entry’s `derived_fact_ids` — so a Q&A answer becomes reusable,
discoverable knowledge rather than being buried in the history.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### refresh(mode='soft', , ingest_fn=None, apply=True)

Refresh `info` from changed sources + undistilled Q&A.

`ingest_fn(item)` supplies extraction (intelligence is external); with
`apply=False` the result is a non-destructive preview. See
[`hired.candidate.refresh`](_autosummary/hired.candidate.html.md#hired.candidate.refresh).

* **Return type:**
  [`RefreshReport`](_autosummary/hired.candidate.html.md#hired.candidate.RefreshReport)

#### regenerate_synopsis()

Rebuild and persist a human-readable synopsis from current facts.

This is a *projection* — always derived from the fact store, never
hand-edited — so it can be regenerated at any time without loss.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### save_upload(name, data)

Store a raw uploaded document by filename (see [`add_source()`](_autosummary/hired.candidate.knowledge_base.html.md#hired.candidate.knowledge_base.CandidateKnowledgeBase.add_source)).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### sources()

Keys of all raw sources the candidate has provided.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### supersede(old_fact_id, new_fact)

Replace `old_fact_id` with `new_fact` (invalidate, don’t delete).

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### *property* synopsis *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

The last persisted synopsis, regenerating it if absent.

#### topic(name)

Get-or-create the dossier for a subject (overview + optional files).

* **Return type:**
  [`TopicDossier`](_autosummary/hired.candidate.topics.html.md#hired.candidate.topics.TopicDossier)

#### topics()

Slugs of all topic dossiers.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]


# _autosummary/hired.candidate.state.html.md

# hired.candidate.state

Refresh bookkeeping: per-source content digests + last-refresh timestamps.

Records a content digest for every raw source the candidate has provided, so a
later refresh can tell which sources are *new* or *changed* since they were last
ingested — without re-reading everything. The state is a singleton persisted at
`user/info/state.json` and is the shared substrate for raw-source tracking
([`add_source()`](_autosummary/hired.candidate.knowledge_base.html.md#hired.candidate.knowledge_base.CandidateKnowledgeBase.add_source)) and
the soft/hard refresh loop.

### Functions

| [`load_state`](_autosummary/hired.candidate.state.html.md#hired.candidate.state.load_state)(user_store)        | Read the refresh state for a `UserStore` (empty if none yet).   |
|--------------------------------------------------------------------------------|-----------------------------------------------------------------|
| [`save_state`](_autosummary/hired.candidate.state.html.md#hired.candidate.state.save_state)(user_store, state) | Persist the refresh state for a `UserStore`.                    |
| [`sha256_hex`](_autosummary/hired.candidate.state.html.md#hired.candidate.state.sha256_hex)(data)              | Content hash used as the change signal for a raw source.        |

### Classes

| [`RefreshState`](_autosummary/hired.candidate.state.html.md#hired.candidate.state.RefreshState)(\*\*data)   | The candidate-info refresh ledger (persisted to `user/info/state.json`).   |
|---------------------------------------------------------------------------|----------------------------------------------------------------------------|
| [`SourceDigest`](_autosummary/hired.candidate.state.html.md#hired.candidate.state.SourceDigest)(\*\*data)   | What we know about one raw source for change detection + provenance.       |

### *class* hired.candidate.state.RefreshState(\*\*data)

Bases: `BaseModel`

The candidate-info refresh ledger (persisted to `user/info/state.json`).

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.candidate.state.SourceDigest(\*\*data)

Bases: `BaseModel`

What we know about one raw source for change detection + provenance.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### hired.candidate.state.load_state(user_store)

Read the refresh state for a `UserStore` (empty if none yet).

* **Return type:**
  [`RefreshState`](_autosummary/hired.candidate.state.html.md#hired.candidate.state.RefreshState)

### hired.candidate.state.save_state(user_store, state)

Persist the refresh state for a `UserStore`.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### hired.candidate.state.sha256_hex(data)

Content hash used as the change signal for a raw source.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)


# _autosummary/hired.candidate.topics.html.md

# hired.candidate.topics

Topic dossiers — “a little, or a whole lot” about any subject the candidate shares.

A dossier lives under `user/info/topics/<slug>/` and holds an `overview.md`
(the human/agent-readable summary and *entry point*) plus optional detail
files/media under `files/`. A one-sentence note and a multi-file collection use
the same shape, so the synopsis can always link to an overview and the agent knows
where deeper detail lives. Reach a dossier via
`kb.topic(name)` / `kb.add_note(name, ...)`.

### Classes

| [`TopicDossier`](_autosummary/hired.candidate.topics.html.md#hired.candidate.topics.TopicDossier)(base_dir, \*[, name])   | One subject's dossier: an `overview.md` plus optional attached files.   |
|---------------------------------------------------------------------------------------|-------------------------------------------------------------------------|

### *class* hired.candidate.topics.TopicDossier(base_dir, , name=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

One subject’s dossier: an `overview.md` plus optional attached files.

```pycon
>>> import tempfile, os
>>> d = TopicDossier(os.path.join(tempfile.mkdtemp(), 'patents'), name='Patents')
>>> d.add_note('Holds 3 US patents on anomaly detection.')
>>> d.overview.splitlines()[0]
'# Patents'
>>> d.add_file('cert.txt', b'patent cert')
>>> d.files()
['cert.txt']
>>> d.get_file('cert.txt')
b'patent cert'
```

#### add_file(filename, data)

Attach a detail file / media blob to the dossier.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### add_note(text)

Append a note to the overview (creating it, titled, if absent).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### exists()

True once the dossier has an overview or any attached file.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

#### files()

Names of attached detail files.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### *property* overview *: [str](https://docs.python.org/3/builtins/stdtypes.html#str) | [None](https://docs.python.org/3/builtins/constants.html#None)*

The dossier’s overview markdown (the entry point), or `None`.


# _autosummary/hired.candidate.workspace.html.md

# hired.candidate.workspace

The per-engagement facade: alignment reports, company research, interview prep.

A [`JDWorkspace`](_autosummary/hired.candidate.workspace.html.md#hired.candidate.workspace.JDWorkspace) is the domain entry point for work on **one engagement** —
one *or a group of* related job descriptions of the same company. It wraps a
[`JDStore`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.JDStore) with validated, intention-revealing
methods and a back-reference to the owning
[`CandidateKnowledgeBase`](_autosummary/hired.candidate.knowledge_base.html.md#hired.candidate.knowledge_base.CandidateKnowledgeBase) (so an alignment
agent has both the candidate’s knowledge and the engagement’s work products at hand).

Obtain one via `kb.jd(jd_id, company=..., label=...)` — never construct directly.

### Classes

| [`JDWorkspace`](_autosummary/hired.candidate.workspace.html.md#hired.candidate.workspace.JDWorkspace)(kb, jd_id, \*[, store])   | Reports, company research, interview-prep briefings, and parsed jobs for one engagement.   |
|----------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|

### *class* hired.candidate.workspace.JDWorkspace(kb, jd_id, , store=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Reports, company research, interview-prep briefings, and parsed jobs for one engagement.

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> from hired.candidate import CandidateKnowledgeBase
>>> kb = CandidateKnowledgeBase()
>>> ws = kb.jd('acme', company='Acme, Inc.', label='Acme roles')
>>> ws.save_report('staff-ds', {'verdict': {'recommendation': 'apply'}})
>>> ws.get_report('staff-ds')['verdict']['recommendation']
'apply'
>>> ws.meta['company']
'Acme, Inc.'
```

#### report_versions(job_id)

Keys of archived prior versions of a job’s report (chronological).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### save_briefing(key, data)

Persist an interview-prep research briefing (keyed by subject/job).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### save_company_report(company, data)

Persist a company/people research report (keyed by company name).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### save_report(job_id, data, , archive=True)

Persist the current alignment report, archiving the prior one first.

Archiving (on by default) snapshots any existing report into
`report_history` so the alignment-review agent can diff versions.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)


# _autosummary/hired.config.html.md

# hired.config

Configuration management using Mapping interfaces.

Implement:

- ConfigStore: MutableMapping for configuration management
- Default configurations
- Configuration merging utilities

### Functions

| `get_default_config`()   |    |
|--------------------------|----|
| `load_config`(path)      |    |

### Classes

| [`ConfigStore`](_autosummary/hired.config.html.md#hired.config.ConfigStore)([base_config])   | Configuration store with cascading defaults.   |
|-------------------------------------------------------------------------------|------------------------------------------------|

### *class* hired.config.ConfigStore(base_config=None)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

Configuration store with cascading defaults.


# _autosummary/hired.content.html.md

# hired.content

Content generation logic and AI agent implementations.

Implement:

- DefaultAIAgent: Basic implementation using local LLM or API
- content source factories for common formats
- content extraction and filtering utilities

### Classes

| [`DefaultAIAgent`](_autosummary/hired.content.html.md#hired.content.DefaultAIAgent)(\*[, model, api_key])         | Default AI agent implementation (mock).                          |
|-----------------------------------------------------------------------------------------------|------------------------------------------------------------------|
| [`DictContentSource`](_autosummary/hired.content.html.md#hired.content.DictContentSource)(data)                      | Implements ContentSource for dictionary data.                    |
| [`FileContentSource`](_autosummary/hired.content.html.md#hired.content.FileContentSource)(path)                      | Implements ContentSource for file-based data.                    |
| [`LLMResumeAgent`](_autosummary/hired.content.html.md#hired.content.LLMResumeAgent)(\*[, model, client, api_key]) | AI agent that tailors a candidate's profile to a job via an LLM. |

### *class* hired.content.DefaultAIAgent(, model='default', api_key=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Default AI agent implementation (mock).

### *class* hired.content.DictContentSource(data)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Implements ContentSource for dictionary data.

### *class* hired.content.FileContentSource(path)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Implements ContentSource for file-based data.

### *class* hired.content.LLMResumeAgent(, model='gpt-4o-mini', client=None, api_key=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

AI agent that tailors a candidate’s profile to a job via an LLM.

Opt-in alternative to [`DefaultAIAgent`](_autosummary/hired.content.html.md#hired.content.DefaultAIAgent) (which is a pass-through). It
is **dependency-injected and lazy**: `openai` is imported only when an agent
is used *without* an injected `client`, so importing `hired` never
requires `openai`, and no API key is read at construction time. Inject a
`client` (anything exposing the OpenAI-style
`chat.completions.create`) to test without network or secrets.

```pycon
>>> class _FakeClient:
...     class chat:
...         class completions:
...             @staticmethod
...             def create(**_):
...                 ...
```


# _autosummary/hired.cover_letter.html.md

# hired.cover_letter

Cover letter generation functionality.

Generate professional cover letters tailored to specific job applications.

### Functions

| [`generate_cover_letter_content`](_autosummary/hired.cover_letter.html.md#hired.cover_letter.generate_cover_letter_content)(...[, tone])    | Generate cover letter content from candidate and job information.   |
|------------------------------------------------------------------------------------------------|---------------------------------------------------------------------|
| [`mk_cover_letter`](_autosummary/hired.cover_letter.html.md#hired.cover_letter.mk_cover_letter)(candidate_info, job_info, \*) | Generate and render a cover letter.                                 |
| [`render_cover_letter`](_autosummary/hired.cover_letter.html.md#hired.cover_letter.render_cover_letter)(cover_letter_data[, ...]) | Render cover letter to specified format.                            |

### Classes

| [`CoverLetterData`](_autosummary/hired.cover_letter.html.md#hired.cover_letter.CoverLetterData)(applicant_name, ...[, ...])   | Data structure for cover letter generation.   |
|------------------------------------------------------------------------------------------------|-----------------------------------------------|

### *class* hired.cover_letter.CoverLetterData(applicant_name, applicant_email, company_name, position_title, applicant_phone=None, applicant_address=None, hiring_manager_name=None, opening_paragraph='', body_paragraphs=None, closing_paragraph='', date=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Data structure for cover letter generation.

#### to_dict()

Convert to dictionary for template rendering.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### hired.cover_letter.generate_cover_letter_content(candidate_info, job_info, tone='professional')

Generate cover letter content from candidate and job information.

* **Parameters:**
  * **candidate_info** ([`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Candidate information (resume dict or basics)
  * **job_info** (`Union`[[`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)], [`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Job information (dict, text, or JobResult)
  * **tone** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Tone of the letter (‘professional’, ‘enthusiastic’, ‘formal’)
* **Return type:**
  [`CoverLetterData`](_autosummary/hired.cover_letter.html.md#hired.cover_letter.CoverLetterData)
* **Returns:**
  CoverLetterData object with generated content

### Examples

```pycon
>>> data = generate_cover_letter_content(
...     candidate_info={'basics': {'name': 'Jane Doe', 'email': 'jane@example.com'}},
...     job_info={'title': 'Software Engineer', 'company': 'TechCorp'},
... )
```

### hired.cover_letter.mk_cover_letter(candidate_info, job_info, , tone='professional', format='text', output_path=None)

Generate and render a cover letter.

* **Parameters:**
  * **candidate_info** ([`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Candidate information (resume dict or basics)
  * **job_info** (`Union`[[`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)], [`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Job information (dict, text, or JobResult)
  * **tone** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Tone of the letter (‘professional’, ‘enthusiastic’, ‘formal’)
  * **format** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Output format (‘text’, ‘html’, ‘markdown’)
  * **output_path** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Optional path to save the cover letter
* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Rendered cover letter as string

### Examples

```pycon
>>> from hired import mk_cover_letter, JobSources, SearchCriteria
>>>
>>> # From job search result
>>> sources = JobSources()
>>> jobs = sources.jobspy.search(SearchCriteria(query="software engineer"))
>>>
>>> letter = mk_cover_letter(
...     candidate_info={'basics': {'name': 'Jane Doe', 'email': 'jane@example.com'}},
...     job_info=jobs[0],
...     format='html'
... )
```

### hired.cover_letter.render_cover_letter(cover_letter_data, format='text', template=None)

Render cover letter to specified format.

* **Parameters:**
  * **cover_letter_data** ([`CoverLetterData`](_autosummary/hired.cover_letter.html.md#hired.cover_letter.CoverLetterData)) – CoverLetterData object
  * **format** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Output format (‘text’, ‘html’, ‘markdown’)
  * **template** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Optional custom Jinja2 template string
* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Rendered cover letter as string


# _autosummary/hired.html.md

# hired

Public API for the hired package.
Import the main user-facing functions and classes.

### *class* hired.ATSChecker

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Check resume for ATS compatibility.

### Examples

```pycon
>>> from hired.ats_checker import ATSChecker
>>>
>>> checker = ATSChecker()
>>> report = checker.check_resume(resume_dict)
>>> print(report.get_summary())
>>>
>>> # Check against specific job
>>> report = checker.check_resume(resume_dict, job_result)
```

#### check_resume(resume_content, job=None)

Check resume for ATS compatibility.

* **Parameters:**
  * **resume_content** ([`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Resume content as dictionary (JSON Resume format)
  * **job** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Optional JobResult to check keyword matching
* **Return type:**
  [`ATSReport`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSReport)
* **Returns:**
  ATSReport with compatibility score and issues

### *class* hired.ATSReport(overall_score, issues=<factory>, keyword_match_score=0.0, matched_keywords=<factory>, missing_keywords=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Report from ATS compatibility check.

#### get_critical_issues()

Get critical issues.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`ATSIssue`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSIssue)]

#### get_issues_by_category(category)

Get issues filtered by category.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`ATSIssue`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSIssue)]

#### get_summary()

Get human-readable summary.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### get_warnings()

Get warnings.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`ATSIssue`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSIssue)]

#### to_dict()

Convert to dictionary.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.AlignmentReport(\*\*data)

Bases: `BaseModel`

A complete, verdict-first alignment analysis for one JD.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.Application(job_title, company, id=None, job_url=None, location=None, salary_range=None, resume_path=None, cover_letter_path=None, status='draft', applied_date=None, created_at=None, updated_at=None, follow_up_date=None, last_contact_date=None, notes='', contacts='', interview_dates='', match_score=None, source=None, source_data='')

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Represents a job application.

#### *classmethod* from_job_result(job, \*\*kwargs)

Create an Application from a JobResult.

* **Parameters:**
  * **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult object
  * **\*\*kwargs** ([`Any`](https://docs.python.org/3/library/typing.html#typing.Any)) – Additional fields to set
* **Return type:**
  [`Application`](_autosummary/hired.tracking.html.md#hired.tracking.Application)
* **Returns:**
  Application object

#### to_dict()

Convert to dictionary.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.ApplicationTracker(db_path=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Track job applications in a SQLite database.

### Examples

```pycon
>>> tracker = ApplicationTracker()
>>>
>>> # Add application from job search
>>> app_id = tracker.add_application(
...     job=job_result,
...     resume_path="resume.pdf",
...     status="applied"
... )
>>>
>>> # Update status
>>> tracker.update_status(app_id, "interview")
>>>
>>> # Get all applications in interview stage
>>> interviews = tracker.get_applications(status="interview")
>>>
>>> # Get statistics
>>> stats = tracker.get_statistics()
```

#### add_application(job=None, \*\*kwargs)

Add a new application.

* **Parameters:**
  * **job** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Optional JobResult to create application from
  * **\*\*kwargs** ([`Any`](https://docs.python.org/3/library/typing.html#typing.Any)) – Additional fields (or all fields if job not provided)
* **Return type:**
  [`int`](https://docs.python.org/3/builtins/functions.html#int)
* **Returns:**
  ID of created application

### Examples

```pycon
>>> # From JobResult
>>> app_id = tracker.add_application(
...     job=job_result,
...     resume_path="resume.pdf",
...     status="applied"
... )
>>>
>>> # Manual entry
>>> app_id = tracker.add_application(
...     job_title="Software Engineer",
...     company="TechCorp",
...     status="applied"
... )
```

#### delete_application(app_id)

Delete an application.

* **Parameters:**
  **app_id** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Application ID
* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if deleted, False if not found

#### export_to_csv(output_path)

Export applications to CSV file.

* **Parameters:**
  **output_path** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Path to output CSV file
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### get_application(app_id)

Get application by ID.

* **Parameters:**
  **app_id** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Application ID
* **Return type:**
  [`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`Application`](_autosummary/hired.tracking.html.md#hired.tracking.Application)]
* **Returns:**
  Application object or None if not found

#### get_applications(status=None, company=None, limit=None)

Get applications with optional filtering.

* **Parameters:**
  * **status** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Filter by status
  * **company** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Filter by company name
  * **limit** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`int`](https://docs.python.org/3/builtins/functions.html#int)]) – Maximum number of results
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`Application`](_autosummary/hired.tracking.html.md#hired.tracking.Application)]
* **Returns:**
  List of Application objects

#### get_follow_ups_due(days=7)

Get applications that need follow-up.

* **Parameters:**
  **days** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of days to look ahead
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`Application`](_autosummary/hired.tracking.html.md#hired.tracking.Application)]
* **Returns:**
  List of Application objects needing follow-up

#### get_statistics()

Get application statistics.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dictionary with statistics

#### update_application(app_id, \*\*kwargs)

Update application fields.

* **Parameters:**
  * **app_id** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Application ID
  * **\*\*kwargs** ([`Any`](https://docs.python.org/3/library/typing.html#typing.Any)) – Fields to update
* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if updated, False if not found

#### update_status(app_id, status, notes=None)

Update application status.

* **Parameters:**
  * **app_id** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Application ID
  * **status** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – New status
  * **notes** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Optional notes to append
* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if updated, False if not found

### *class* hired.CandidateKnowledgeBase(user='me', , store=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Accumulated, open-world knowledge about a single candidate (user-level).

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> kb = CandidateKnowledgeBase()                 # default candidate "me"
>>> from hired.candidate.base import Fact, FactCategory
>>> _ = kb.add_fact(Fact(statement='Built ML pipelines in Python',
...                       category=FactCategory.SKILL, tags=['python', 'ml']))
>>> [f.statement for f in kb.facts(category=FactCategory.SKILL)]
['Built ML pipelines in Python']
>>> [f.statement for f in kb.facts(tags=['ml'])]
['Built ML pipelines in Python']
```

#### add_fact(fact)

Persist a fact, returning its id.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### add_note(subject, text=None, , files=None)

Record volunteered info about a subject into its dossier.

`text` is appended to the dossier’s `overview.md`; `files` (a
`{name: bytes}` mapping) are attached as detail/media. Returns the
dossier. This is the “by the way, I also did X” entry point — a single
sentence or a whole folder both land here.

* **Return type:**
  [`TopicDossier`](_autosummary/hired.candidate.topics.html.md#hired.candidate.topics.TopicDossier)

#### add_source(src, , name=None)

Store a raw source (file path or bytes) and record its content digest.

Returns the source key (its name in the raw store). The digest (in
`state.json`) lets a later refresh detect new/changed sources without
re-reading everything. Facts extracted from a source cite it by this key.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### facts(, category=None, tags=None, status=FactStatus.ASSERTED, include_negations=True)

Iterate facts, optionally filtered by category/tags/status.

By default only `ASSERTED` facts are returned (superseded ones are
hidden). `tags` matches facts containing *any* of the given tags.

* **Return type:**
  [`Iterator`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator)[[`Fact`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.Fact)]

#### jd(jd_id, , company=None, label=None)

Get-or-create the workspace for an engagement (1+ JDs of one company).

`company` / `label` are recorded in the engagement’s `meta` when given.

* **Return type:**
  [`JDWorkspace`](_autosummary/hired.candidate.workspace.html.md#hired.candidate.workspace.JDWorkspace)

#### jds()

Ids of all engagements for this candidate.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### needs_refresh()

True when uningested source/Q&A material exists (refresh warranted).

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

#### pending_qa()

Q&A entries not yet distilled into facts.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`QAEntry`](_autosummary/hired.candidate.base.html.md#hired.candidate.base.QAEntry)]

#### pending_sources()

Raw sources new, changed, or not yet distilled into facts.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### record_qa(entry, , derived_facts=None)

Append a clarifying Q&A exchange; optionally distill it into facts.

When `derived_facts` (atomic fact records extracted from the answer) are
given, they are ingested with `SourceKind.QA` provenance (`source_id`
= the Q&A id, quotes verified against the answer) and back-linked via the
entry’s `derived_fact_ids` — so a Q&A answer becomes reusable,
discoverable knowledge rather than being buried in the history.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### refresh(mode='soft', , ingest_fn=None, apply=True)

Refresh `info` from changed sources + undistilled Q&A.

`ingest_fn(item)` supplies extraction (intelligence is external); with
`apply=False` the result is a non-destructive preview. See
[`hired.candidate.refresh`](_autosummary/hired.candidate.html.md#hired.candidate.refresh).

* **Return type:**
  [`RefreshReport`](_autosummary/hired.candidate.html.md#hired.candidate.RefreshReport)

#### regenerate_synopsis()

Rebuild and persist a human-readable synopsis from current facts.

This is a *projection* — always derived from the fact store, never
hand-edited — so it can be regenerated at any time without loss.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### save_upload(name, data)

Store a raw uploaded document by filename (see [`add_source()`](_autosummary/hired.html.md#hired.CandidateKnowledgeBase.add_source)).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### sources()

Keys of all raw sources the candidate has provided.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### supersede(old_fact_id, new_fact)

Replace `old_fact_id` with `new_fact` (invalidate, don’t delete).

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### *property* synopsis *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

The last persisted synopsis, regenerating it if absent.

#### topic(name)

Get-or-create the dossier for a subject (overview + optional files).

* **Return type:**
  [`TopicDossier`](_autosummary/hired.candidate.topics.html.md#hired.candidate.topics.TopicDossier)

#### topics()

Slugs of all topic dossiers.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### *class* hired.CoverLetterData(applicant_name, applicant_email, company_name, position_title, applicant_phone=None, applicant_address=None, hiring_manager_name=None, opening_paragraph='', body_paragraphs=None, closing_paragraph='', date=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Data structure for cover letter generation.

#### to_dict()

Convert to dictionary for template rendering.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.DefaultAIAgent(, model='default', api_key=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Default AI agent implementation (mock).

### *class* hired.JDWorkspace(kb, jd_id, , store=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Reports, company research, interview-prep briefings, and parsed jobs for one engagement.

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> from hired.candidate import CandidateKnowledgeBase
>>> kb = CandidateKnowledgeBase()
>>> ws = kb.jd('acme', company='Acme, Inc.', label='Acme roles')
>>> ws.save_report('staff-ds', {'verdict': {'recommendation': 'apply'}})
>>> ws.get_report('staff-ds')['verdict']['recommendation']
'apply'
>>> ws.meta['company']
'Acme, Inc.'
```

#### report_versions(job_id)

Keys of archived prior versions of a job’s report (chronological).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### save_briefing(key, data)

Persist an interview-prep research briefing (keyed by subject/job).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### save_company_report(company, data)

Persist a company/people research report (keyed by company name).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### save_report(job_id, data, , archive=True)

Persist the current alignment report, archiving the prior one first.

Archiving (on by default) snapshots any existing report into
`report_history` so the alignment-review agent can diff versions.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.JobAnalyzer(job)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Analyze job postings to extract key information for resume tailoring.

#### extract_keywords(top_n=20)

Extract most important keywords from job posting.

* **Parameters:**
  **top_n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of top keywords to return
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of keywords sorted by relevance

#### extract_requirements()

Extract job requirements from description.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of requirement strings

#### extract_skills(include_soft_skills=True)

Extract mentioned skills from job posting.

* **Parameters:**
  **include_soft_skills** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – Whether to include soft skills
* **Return type:**
  [`Set`](https://docs.python.org/3/library/typing.html#typing.Set)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  Set of identified skills

#### get_summary()

Get a summary of the job posting.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dictionary with job summary

#### to_job_info_text()

Convert job posting to a formatted text suitable for resume generation.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Formatted job description text

### *class* hired.JobMatcher(candidate_skills=None, candidate_keywords=None, required_skills=None, min_salary=None, max_salary=None, preferred_locations=None, remote_only=False)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Match candidate profiles against job postings.

### Examples

```pycon
>>> matcher = JobMatcher(candidate_skills=['python', 'django', 'aws'])
>>> scores = matcher.score_jobs(job_results)
>>> top_jobs = matcher.get_top_matches(job_results, n=10)
```

#### filter_jobs(jobs, min_score=50.0)

Filter jobs that meet minimum score threshold.

* **Parameters:**
  * **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
  * **min_score** ([`float`](https://docs.python.org/3/builtins/functions.html#float)) – Minimum score threshold (0-100)
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects that meet threshold

#### get_recommendations(jobs, top_n=5)

Get human-readable recommendations based on job matches.

* **Parameters:**
  * **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
  * **top_n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of top jobs to include in recommendations
* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Formatted recommendation string

#### get_top_matches(jobs, n=10, min_score=0.0)

Get top N job matches sorted by score.

* **Parameters:**
  * **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
  * **n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of top matches to return
  * **min_score** ([`float`](https://docs.python.org/3/builtins/functions.html#float)) – Minimum score threshold (0-100)
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`MatchScore`](_autosummary/hired.matching.html.md#hired.matching.MatchScore)]
* **Returns:**
  List of MatchScore objects sorted by overall_score descending

#### identify_skill_gaps(jobs)

Identify skills frequently requested but not possessed by candidate.

* **Parameters:**
  **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects to analyze
* **Returns:**
  frequency} for missing skills
* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`int`](https://docs.python.org/3/builtins/functions.html#int)]

#### score_job(job)

Score a single job against candidate profile.

* **Parameters:**
  **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult to score
* **Return type:**
  [`MatchScore`](_autosummary/hired.matching.html.md#hired.matching.MatchScore)
* **Returns:**
  MatchScore object

#### score_jobs(jobs)

Score multiple jobs.

* **Parameters:**
  **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`MatchScore`](_autosummary/hired.matching.html.md#hired.matching.MatchScore)]
* **Returns:**
  List of MatchScore objects

### *class* hired.JobResult(title, source, company=None, company_url=None, job_url=None, location=None, is_remote=None, description=None, job_type=None, compensation=None, date_posted=None, date_updated=None, application_deadline=None, skills=<factory>, benefits=<factory>, emails=<factory>, raw_data=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Standardized job result across all sources.

This provides a unified interface regardless of which source
the job was retrieved from.

#### to_dict()

Convert JobResult to dictionary.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.JobSearchSource

Bases: [`ABC`](https://docs.python.org/3/library/abc.html#abc.ABC)

Abstract base class for job search sources.

All job search sources must implement this interface to be
registered in the system.

#### *abstract property* display_name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the display name of this source (e.g., ‘Indeed’, ‘USAJobs’).

#### *abstractmethod* get_setup_instructions()

Return setup instructions for this source.

Should include:

- Where to get API keys if needed
- Environment variables or config file settings
- URLs for documentation

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Multi-line string with setup instructions.

#### *abstractmethod* is_configured()

Check if this source is properly configured.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if the source is ready to use, False otherwise.

#### *abstract property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the name of this source (e.g., ‘indeed’, ‘usajobs’).

#### *abstract property* requires_auth *: [bool](https://docs.python.org/3/builtins/functions.html#bool)*

Return True if this source requires authentication/API keys.

#### *abstractmethod* search(criteria)

Search for jobs using the given criteria.

* **Parameters:**
  **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – SearchCriteria object with search parameters
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects
* **Raises:**
  * [**SourceConfigError**](_autosummary/hired.search.html.md#hired.search.SourceConfigError) – If the source is not properly configured
  * [**Exception**](https://docs.python.org/3/builtins/exceptions.html#Exception) – For other errors during search

#### validate_configured()

Validate that the source is configured, raise error if not.

* **Raises:**
  [**SourceConfigError**](_autosummary/hired.search.html.md#hired.search.SourceConfigError) – If the source is not properly configured
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.JobSources(registry=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Main facade for accessing job search sources.

Provides both mapping interface (dict-like access) and attribute access
to registered job sources.

### Examples

```pycon
>>> sources = JobSources()
>>> # List all available sources
>>> sources.list()
['jobspy', 'usajobs', 'adzuna']
```

```pycon
>>> # Access via attribute
>>> results = sources.jobspy.search(SearchCriteria(query="python developer"))
```

```pycon
>>> # Access via mapping
>>> results = sources['indeed'].search(SearchCriteria(query="data scientist"))
```

```pycon
>>> # Search across multiple sources
>>> results = sources.search_all(
...     SearchCriteria(query="software engineer", location="San Francisco")
... )
```

#### get_info(name)

Get information about a source.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dictionary with source information including setup instructions

#### get_source(name)

Get a source by name.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)
* **Returns:**
  JobSearchSource instance
* **Raises:**
  [**KeyError**](https://docs.python.org/3/builtins/exceptions.html#KeyError) – If source not found

#### keys()

Get list of source names (dict-like interface).

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### list()

List all registered sources.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of source names

#### list_available()

List sources that are configured and ready to use.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of configured source names

#### list_unconfigured()

List sources that need configuration.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of unconfigured source names

#### print_status()

Print the status of all registered sources.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### search(source_name, criteria)

Search using a specific source.

* **Parameters:**
  * **source_name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source to use
  * **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects

#### search_all(criteria, sources=None, skip_unconfigured=True)

Search across multiple sources.

* **Parameters:**
  * **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
  * **sources** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]) – Optional list of source names. If None, uses all available sources.
  * **skip_unconfigured** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – If True, skip sources that are not configured
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  Combined list of JobResult objects from all sources

### *class* hired.JobType(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Standardized job types across all sources.

### *class* hired.LLMConfig(model, temperature=0.7, max_tokens=None, top_p=1.0, provider='openai', api_key=None, base_url=None, extra_params=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Configuration for LLM model selection and parameters.

```pycon
>>> config = LLMConfig(model="gpt-4", temperature=0.7)
>>> config.model
'gpt-4'
```

#### to_dspy_lm()

Convert to DSPy LM instance.

* **Return type:**
  [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)

#### to_langchain_kwargs()

Convert to LangChain model kwargs.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.LLMResumeAgent(, model='gpt-4o-mini', client=None, api_key=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

AI agent that tailors a candidate’s profile to a job via an LLM.

Opt-in alternative to [`DefaultAIAgent`](_autosummary/hired.html.md#hired.DefaultAIAgent) (which is a pass-through). It
is **dependency-injected and lazy**: `openai` is imported only when an agent
is used *without* an injected `client`, so importing `hired` never
requires `openai`, and no API key is read at construction time. Inject a
`client` (anything exposing the OpenAI-style
`chat.completions.create`) to test without network or secrets.

```pycon
>>> class _FakeClient:
...     class chat:
...         class completions:
...             @staticmethod
...             def create(**_):
...                 ...
```

### *class* hired.MatchScore(job, overall_score, skill_match_score, keyword_match_score, matched_skills=<factory>, missing_skills=<factory>, matched_keywords=<factory>, compensation_match=None, location_match=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Score for a job match.

#### get_summary()

Get human-readable summary.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### to_dict()

Convert to dictionary.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.RenderingConfig(format='pdf', theme='default', custom_css=None, custom_template=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Configuration for resume rendering.

### *class* hired.Requirement(\*\*data)

Bases: `BaseModel`

One atomic requirement extracted verbatim from a job description.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.RequirementRecord(\*\*data)

Bases: `BaseModel`

The analysis of one requirement against the candidate’s knowledge.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### hired.ResumeContent

alias of [`ResumeSchemaExtended`](_autosummary/hired.base.html.md#hired.base.ResumeSchemaExtended)

### *class* hired.ResumeExpertAgent(, llm_config=None, model_registry=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Autonomous agent that uses ResumeSession as a tool.

Operates in auto mode, making decisions about expansion, distillation,
search, and generation operations to produce complete resumes.

```pycon
>>> config = LLMConfig(model="gpt-4")
>>> agent = ResumeExpertAgent(llm_config=config)
>>> agent.llm_config.model
'gpt-4'
```

#### create_resume(session, , mode='standard', max_iterations=5)

Autonomously create resume using session as tool.

Operates in plan-and-execute pattern:

1. Analyze job and candidate info
2. Plan resume creation strategy
3. Execute operations (expand, distill, match)
4. Generate resume
5. Critique and refine

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### execute_plan(session, plan, , interactive=False, approval_callback=None)

Execute a plan step by step.

* **Parameters:**
  * **session** ([`ResumeSession`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ResumeSession)) – Resume session to operate on
  * **plan** ([`Plan`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Plan)) – Plan to execute
  * **interactive** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – If True, pause after each step for approval
* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dict with execution results and final outputs

#### propose_plan(session, , mode='standard')

Generate execution plan for resume creation.

Returns structured Plan object that can be edited before execution.

* **Return type:**
  [`Plan`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Plan)

#### revise_plan(plan, instruction)

Revise plan based on natural language instruction.

Uses LLM to interpret instruction and modify plan accordingly.

* **Return type:**
  [`Plan`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Plan)

### *class* hired.ResumeSchema(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'forbid'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.ResumeSchemaExtended(\*\*data)

Bases: [`ResumeSchema`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.ResumeSchema)

Extended version of ResumeSchema that allows extra fields for custom sections.

This class inherits all the validation and structure from ResumeSchema
but allows additional fields to be stored for custom sections.

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.ResumeSession(job_info, candidate_info, , mode=OperationMode.MANUAL, system_prompt=None, max_recent_turns=10, llm_config=None, model_registry=None, auto_persist=True, data_dir=None, name=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Stateful conversation session for resume creation.

Provides manual chat interface where users give natural language
instructions to perform expansion, distillation, search, and generation
operations. Maintains conversation history and structured state.

```pycon
>>> config = LLMConfig("gpt-4")
>>> session = ResumeSession(
...     job_info="Senior ML Engineer at TechCo",
...     candidate_info="5 years Python, ML experience",
...     llm_config=config
... )
>>> session.llm_config.model
'gpt-4'
```

#### chat(user_message)

Process user instruction and return assistant response.

This is the main interface for manual mode operation.
Automatically persists session after each turn if auto_persist enabled.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### *property* history *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[Turn](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Turn)]*

Get all conversation turns.

#### *classmethod* list_persisted(data_dir=None)

List all persisted sessions.

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]

```pycon
>>> for session_info in ResumeSession.list_persisted():
...     print(session_info['session_id'])
```

#### *classmethod* load(session_id, , data_dir=None, llm_config=None)

Load session from persistent storage.

* **Return type:**
  [`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`ResumeSession`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ResumeSession)]

```pycon
>>> session = ResumeSession.load("abc123def456")
>>> session.session_id if session else None
'abc123def456'
```

#### *property* metadata *: [dict](https://docs.python.org/3/builtins/stdtypes.html#dict)[[str](https://docs.python.org/3/builtins/stdtypes.html#str), [Any](https://docs.python.org/3/library/typing.html#typing.Any)]*

Return a small metadata dict for quick inspection.

Includes: session_id, name, created_at (iso), n_turns, mode, model

#### save(data_dir=None)

Manually save session to persistent storage.

Returns path to saved session file.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

#### *property* snapshots *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[SessionSnapshot](_autosummary/hired.resume_agent.html.md#hired.resume_agent.SessionSnapshot)]*

Get all session snapshots.

#### *property* state *: [SessionState](_autosummary/hired.resume_agent.html.md#hired.resume_agent.SessionState)*

Get current session state.

#### switch_mode(mode)

Switch between manual and auto operation modes.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.SearchCriteria(query, location=None, country=None, city=None, state=None, postal_code=None, distance_miles=None, job_type=None, is_remote=None, posted_within_days=None, results_wanted=20, offset=0, min_salary=None, max_salary=None, keywords=<factory>, exclude_keywords=<factory>, source_params=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Standardized search criteria across all sources.

Different sources may not support all criteria, but this provides
a consistent interface for users.

### hired.check_resume_ats(resume_content, job=None)

Quick utility to check resume ATS compatibility.

* **Parameters:**
  * **resume_content** ([`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Resume content as dictionary (JSON Resume format)
  * **job** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Optional JobResult for keyword matching
* **Return type:**
  [`ATSReport`](_autosummary/hired.ats_checker.html.md#hired.ats_checker.ATSReport)
* **Returns:**
  ATSReport

### Examples

```pycon
>>> from hired import mk_content_for_resume
>>> from hired.ats_checker import check_resume_ats
>>>
>>> resume = mk_content_for_resume(candidate_info, job_info)
>>> report = check_resume_ats(resume.model_dump(), job_result)
>>> print(report.get_summary())
```

### hired.classify(record)

Fill `gap_size` and `bucket` (and `needs_clarification`) in place.

Returns the same record for convenience.

* **Return type:**
  [`RequirementRecord`](_autosummary/hired.alignment.base.html.md#hired.alignment.base.RequirementRecord)

### hired.extract_job_keywords(job, top_n=20)

Extract top keywords from a job posting.

* **Parameters:**
  * **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult object
  * **top_n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of keywords to return
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of top keywords

### hired.generate_cover_letter_content(candidate_info, job_info, tone='professional')

Generate cover letter content from candidate and job information.

* **Parameters:**
  * **candidate_info** ([`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Candidate information (resume dict or basics)
  * **job_info** (`Union`[[`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)], [`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Job information (dict, text, or JobResult)
  * **tone** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Tone of the letter (‘professional’, ‘enthusiastic’, ‘formal’)
* **Return type:**
  [`CoverLetterData`](_autosummary/hired.cover_letter.html.md#hired.cover_letter.CoverLetterData)
* **Returns:**
  CoverLetterData object with generated content

### Examples

```pycon
>>> data = generate_cover_letter_content(
...     candidate_info={'basics': {'name': 'Jane Doe', 'email': 'jane@example.com'}},
...     job_info={'title': 'Software Engineer', 'company': 'TechCorp'},
... )
```

### hired.get_job_skills(job)

Extract skills mentioned in job posting.

* **Parameters:**
  **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult object
* **Return type:**
  [`Set`](https://docs.python.org/3/library/typing.html#typing.Set)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  Set of skills

### hired.job_to_text(job)

Convert a JobResult to formatted text for resume generation.

* **Parameters:**
  **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult object
* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Formatted text description

### hired.mk_content_for_resume(candidate_info_src, job_info_src, , agent=None, validate=True, strict=False)

Generate resume content from candidate and job information.

* **Parameters:**
  * **candidate_info_src** (`Union`[[`ContentSource`](_autosummary/hired.base.html.md#hired.base.ContentSource), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]) – Candidate information as ContentSource, file path, or dict
  * **job_info_src** (`Union`[[`ContentSource`](_autosummary/hired.base.html.md#hired.base.ContentSource), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)], [`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Job information as ContentSource, file path, dict, or JobResult
  * **agent** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Optional AI agent for content generation
  * **validate** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – Whether to validate the generated content
  * **strict** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – Whether to use strict validation
* **Return type:**
  [`ResumeSchemaExtended`](_autosummary/hired.base.html.md#hired.base.ResumeSchemaExtended)
* **Returns:**
  ResumeSchemaExtended object with generated content

### Examples

```pycon
>>> # Using file paths
>>> content = mk_content_for_resume("candidate.json", "job.txt")
>>>
>>> # Using JobResult from job search
>>> from hired import JobSources, SearchCriteria
>>> sources = JobSources()
>>> jobs = sources.jobspy.search(SearchCriteria(query="python developer"))
>>> content = mk_content_for_resume(candidate_dict, jobs[0])
```

### hired.mk_cover_letter(candidate_info, job_info, , tone='professional', format='text', output_path=None)

Generate and render a cover letter.

* **Parameters:**
  * **candidate_info** ([`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Candidate information (resume dict or basics)
  * **job_info** (`Union`[[`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)], [`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Job information (dict, text, or JobResult)
  * **tone** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Tone of the letter (‘professional’, ‘enthusiastic’, ‘formal’)
  * **format** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Output format (‘text’, ‘html’, ‘markdown’)
  * **output_path** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Optional path to save the cover letter
* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Rendered cover letter as string

### Examples

```pycon
>>> from hired import mk_cover_letter, JobSources, SearchCriteria
>>>
>>> # From job search result
>>> sources = JobSources()
>>> jobs = sources.jobspy.search(SearchCriteria(query="software engineer"))
>>>
>>> letter = mk_cover_letter(
...     candidate_info={'basics': {'name': 'Jane Doe', 'email': 'jane@example.com'}},
...     job_info=jobs[0],
...     format='html'
... )
```

### hired.mk_resume(content, rendering=None, , output_path=None, strict=False)

Render resume content to final format.

* **Return type:**
  [`bytes`](https://docs.python.org/3/builtins/stdtypes.html#bytes)

### hired.quick_match(candidate_skills, jobs, top_n=10)

Quick utility function to match jobs against candidate skills.

* **Parameters:**
  * **candidate_skills** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – List of candidate’s skills
  * **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
  * **top_n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of top matches to return
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`MatchScore`](_autosummary/hired.matching.html.md#hired.matching.MatchScore)]
* **Returns:**
  List of top MatchScore objects

### Examples

```pycon
>>> from hired import JobSources, SearchCriteria
>>> from hired.matching import quick_match
>>>
>>> sources = JobSources()
>>> jobs = sources.jobspy.search(SearchCriteria(query="python developer"))
>>>
>>> matches = quick_match(
...     candidate_skills=['python', 'django', 'postgresql'],
...     jobs=jobs,
...     top_n=5
... )
>>>
>>> for match in matches:
...     print(match.get_summary())
```

### hired.render_report_markdown(report)

Render the report as a Markdown string.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### Modules

| [`alignment`](_autosummary/hired.alignment.html.md#module-hired.alignment)                                   | JD-vs-candidate alignment: classify each requirement honestly into four buckets.   |
|---------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------|
| [`ats_checker`](_autosummary/hired.ats_checker.html.md#module-hired.ats_checker)                               | ATS (Applicant Tracking System) compatibility checker.                             |
| [`base`](_autosummary/hired.base.html.md#module-hired.base)                                             | Core data models and protocols for the hired package.                              |
| [`candidate`](_autosummary/hired.candidate.html.md#module-hired.candidate)                                   | Candidate knowledge domain: accumulate open-world facts about a candidate.         |
| [`config`](_autosummary/hired.config.html.md#module-hired.config)                                         | Configuration management using Mapping interfaces.                                 |
| [`content`](_autosummary/hired.content.html.md#module-hired.content)                                       | Content generation logic and AI agent implementations.                             |
| [`cover_letter`](_autosummary/hired.cover_letter.html.md#module-hired.cover_letter)                             | Cover letter generation functionality.                                             |
| [`job_utils`](_autosummary/hired.job_utils.html.md#module-hired.job_utils)                                   | Utilities for working with job postings and matching them to resumes.              |
| [`matching`](_autosummary/hired.matching.html.md#module-hired.matching)                                     | Job matching and scoring utilities.                                                |
| [`persistence`](_autosummary/hired.persistence.html.md#module-hired.persistence)                               | dol-based persistence foundation for hired (Storage v2).                           |
| [`render`](_autosummary/hired.render.html.md#module-hired.render)                                         | Rendering pipeline and theme management.                                           |
| [`renderers`](_autosummary/hired.renderers.html.md#module-hired.renderers)                                   | Renderer implementations package.                                                  |
| [`resume_agent`](_autosummary/hired.resume_agent.html.md#module-hired.resume_agent)                             | Resume Generation System - Core Architecture                                       |
| [`resumejson_pydantic_models`](_autosummary/hired.resumejson_pydantic_models.html.md#module-hired.resumejson_pydantic_models) | Pydantic models for resume json schema                                             |
| [`search`](_autosummary/hired.search.html.md#module-hired.search)                                         | Job search functionality for the hired package.                                    |
| [`tools`](_autosummary/hired.tools.html.md#module-hired.tools)                                           | High-level orchestration functions - the main API.                                 |
| [`tracking`](_autosummary/hired.tracking.html.md#module-hired.tracking)                                     | Application tracking system for managing job applications.                         |
| [`util`](_autosummary/hired.util.html.md#module-hired.util)                                             | Utilities for external dependencies and general helpers.                           |


# _autosummary/hired.job_utils.html.md

# hired.job_utils

Utilities for working with job postings and matching them to resumes.

### Functions

| [`extract_job_keywords`](_autosummary/hired.job_utils.html.md#hired.job_utils.extract_job_keywords)(job[, top_n])   | Extract top keywords from a job posting.                     |
|---------------------------------------------------------------------------------------|--------------------------------------------------------------|
| [`get_job_skills`](_autosummary/hired.job_utils.html.md#hired.job_utils.get_job_skills)(job)                  | Extract skills mentioned in job posting.                     |
| [`job_to_text`](_autosummary/hired.job_utils.html.md#hired.job_utils.job_to_text)(job)                     | Convert a JobResult to formatted text for resume generation. |

### Classes

| [`JobAnalyzer`](_autosummary/hired.job_utils.html.md#hired.job_utils.JobAnalyzer)(job)   | Analyze job postings to extract key information for resume tailoring.   |
|---------------------------------------------------------------------|-------------------------------------------------------------------------|

### *class* hired.job_utils.JobAnalyzer(job)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Analyze job postings to extract key information for resume tailoring.

#### extract_keywords(top_n=20)

Extract most important keywords from job posting.

* **Parameters:**
  **top_n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of top keywords to return
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of keywords sorted by relevance

#### extract_requirements()

Extract job requirements from description.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of requirement strings

#### extract_skills(include_soft_skills=True)

Extract mentioned skills from job posting.

* **Parameters:**
  **include_soft_skills** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – Whether to include soft skills
* **Return type:**
  [`Set`](https://docs.python.org/3/library/typing.html#typing.Set)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  Set of identified skills

#### get_summary()

Get a summary of the job posting.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dictionary with job summary

#### to_job_info_text()

Convert job posting to a formatted text suitable for resume generation.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Formatted job description text

### hired.job_utils.extract_job_keywords(job, top_n=20)

Extract top keywords from a job posting.

* **Parameters:**
  * **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult object
  * **top_n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of keywords to return
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of top keywords

### hired.job_utils.get_job_skills(job)

Extract skills mentioned in job posting.

* **Parameters:**
  **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult object
* **Return type:**
  [`Set`](https://docs.python.org/3/library/typing.html#typing.Set)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  Set of skills

### hired.job_utils.job_to_text(job)

Convert a JobResult to formatted text for resume generation.

* **Parameters:**
  **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult object
* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Formatted text description


# _autosummary/hired.matching.html.md

# hired.matching

Job matching and scoring utilities.

Match candidate profiles against job postings to identify the best opportunities.

### Functions

| [`quick_match`](_autosummary/hired.matching.html.md#hired.matching.quick_match)(candidate_skills, jobs[, top_n])   | Quick utility function to match jobs against candidate skills.   |
|-------------------------------------------------------------------------------------------------|------------------------------------------------------------------|

### Classes

| [`JobMatcher`](_autosummary/hired.matching.html.md#hired.matching.JobMatcher)([candidate_skills, ...])        | Match candidate profiles against job postings.   |
|---------------------------------------------------------------------------------------------|--------------------------------------------------|
| [`MatchScore`](_autosummary/hired.matching.html.md#hired.matching.MatchScore)(job, overall_score, ...[, ...]) | Score for a job match.                           |

### *class* hired.matching.JobMatcher(candidate_skills=None, candidate_keywords=None, required_skills=None, min_salary=None, max_salary=None, preferred_locations=None, remote_only=False)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Match candidate profiles against job postings.

### Examples

```pycon
>>> matcher = JobMatcher(candidate_skills=['python', 'django', 'aws'])
>>> scores = matcher.score_jobs(job_results)
>>> top_jobs = matcher.get_top_matches(job_results, n=10)
```

#### filter_jobs(jobs, min_score=50.0)

Filter jobs that meet minimum score threshold.

* **Parameters:**
  * **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
  * **min_score** ([`float`](https://docs.python.org/3/builtins/functions.html#float)) – Minimum score threshold (0-100)
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects that meet threshold

#### get_recommendations(jobs, top_n=5)

Get human-readable recommendations based on job matches.

* **Parameters:**
  * **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
  * **top_n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of top jobs to include in recommendations
* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Formatted recommendation string

#### get_top_matches(jobs, n=10, min_score=0.0)

Get top N job matches sorted by score.

* **Parameters:**
  * **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
  * **n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of top matches to return
  * **min_score** ([`float`](https://docs.python.org/3/builtins/functions.html#float)) – Minimum score threshold (0-100)
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`MatchScore`](_autosummary/hired.matching.html.md#hired.matching.MatchScore)]
* **Returns:**
  List of MatchScore objects sorted by overall_score descending

#### identify_skill_gaps(jobs)

Identify skills frequently requested but not possessed by candidate.

* **Parameters:**
  **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects to analyze
* **Returns:**
  frequency} for missing skills
* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`int`](https://docs.python.org/3/builtins/functions.html#int)]

#### score_job(job)

Score a single job against candidate profile.

* **Parameters:**
  **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult to score
* **Return type:**
  [`MatchScore`](_autosummary/hired.matching.html.md#hired.matching.MatchScore)
* **Returns:**
  MatchScore object

#### score_jobs(jobs)

Score multiple jobs.

* **Parameters:**
  **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`MatchScore`](_autosummary/hired.matching.html.md#hired.matching.MatchScore)]
* **Returns:**
  List of MatchScore objects

### *class* hired.matching.MatchScore(job, overall_score, skill_match_score, keyword_match_score, matched_skills=<factory>, missing_skills=<factory>, matched_keywords=<factory>, compensation_match=None, location_match=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Score for a job match.

#### get_summary()

Get human-readable summary.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### to_dict()

Convert to dictionary.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### hired.matching.quick_match(candidate_skills, jobs, top_n=10)

Quick utility function to match jobs against candidate skills.

* **Parameters:**
  * **candidate_skills** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – List of candidate’s skills
  * **jobs** ([`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – List of JobResult objects
  * **top_n** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of top matches to return
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`MatchScore`](_autosummary/hired.matching.html.md#hired.matching.MatchScore)]
* **Returns:**
  List of top MatchScore objects

### Examples

```pycon
>>> from hired import JobSources, SearchCriteria
>>> from hired.matching import quick_match
>>>
>>> sources = JobSources()
>>> jobs = sources.jobspy.search(SearchCriteria(query="python developer"))
>>>
>>> matches = quick_match(
...     candidate_skills=['python', 'django', 'postgresql'],
...     jobs=jobs,
...     top_n=5
... )
>>>
>>> for match in matches:
...     print(match.get_summary())
```


# _autosummary/hired.persistence.base.html.md

# hired.persistence.base

Canonical data root, filesystem codecs, and the two-level candidate layout.

The canonical root is resolved by [`app_data_dir()`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.app_data_dir), honoring (in order):

1. the `HIRED_DATA_DIR` environment variable (used by tests and power users),
2. `$XDG_DATA_HOME/hired` (the XDG Base Directory spec),
3. `~/.local/share/hired` (the XDG default).

**Storage v2 — two-level layout.** Per-candidate data is split into \*what is true
about the candidate\* (cross-JD, reusable) and *work on a specific company’s role(s)*:

```default
users/<user>/
  user/                      # the candidate — single source of truth
    raw/                     # raw sources the user provided (bytes; real filenames)
    info/                    # agent-maintained, operable knowledge (agent CRUDs here)
      facts/  <id>.json
      qa/     <id>.json
      topics/ <topic>/...    # per-subject dossiers (Phase 2)
      synopsis.md            # regenerated overview (singleton)
      state.json             # refresh bookkeeping (Phase 3)
  jds/<jd_id>/               # one engagement = 1+ related JDs of the same company
    meta.json
    jobs/ reports/ report_history/ company/ interview_prep/   (<key>.json)
```

**Codecs (the extension fix).** Keys stay domain-oriented and *extension-less* on the
`MutableMapping` facade; file extensions live only on the filesystem side, applied by
`dol` key codecs, and values are dicts in Python / JSON on disk via value codecs:

- [`json_store()`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.json_store) — `JsonFiles` + a `.json` key codec: bare-id keys, `<id>.json`
  files, dict values.
- [`markdown_store()`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.markdown_store) — `TextFiles` + a `.md` key codec: bare keys, `<key>.md`
  files, `str` values.
- [`bytes_store()`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.bytes_store) — `dol.Files`: keys are real filenames (extension kept, as
  the extension is the meaningful domain key for an upload like `cv.pdf`).

The key codec uses only dol’s core `wrap_kvs` (not `affix_key_codec`/`filt_iter`,
which has a Windows-specific bug in dol 0.3.x) and normalizes path separators, so stores
behave identically on POSIX and Windows.

[`UserStore`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.UserStore) groups the user-level stores; [`JDStore`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.JDStore) groups one engagement’s
stores. Singletons (`synopsis.md`, `state.json`, `meta.json`) are single files —
their accessors carry the extension in the path, never in a store key.

### Module Attributes

| [`JsonStore`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.JsonStore)   | A store of JSON-able values (dicts in Python, JSON on disk), keyed by bare ids.   |
|--------------------------------------------------------------|-----------------------------------------------------------------------------------|
| [`TextStore`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.TextStore)   | A store of `str` values (e.g. markdown files), keyed by bare names.               |
| [`BytesStore`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.BytesStore)  | A store of raw `bytes`, keyed by real filenames.                                  |

### Functions

| [`app_data_dir`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.app_data_dir)(\*subpaths[, make])         | Return the canonical hired data directory, joined with `subpaths`.           |
|-------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
| [`bytes_store`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.bytes_store)(rootdir)                     | A `MutableMapping` of raw `bytes`; keys are real filenames (extension kept). |
| [`json_store`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.json_store)(rootdir)                      | A `MutableMapping` of JSON-able values: bare-id keys, `<id>.json` files.     |
| [`list_jds`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.list_jds)([user, root])                   | Engagement ids under `users/<user>/jds/` (sorted; empty if none).            |
| [`markdown_store`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.markdown_store)(rootdir)                  | A `MutableMapping` of `str` values: bare keys, `<key>.md` files.             |
| [`migrate_legacy`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.migrate_legacy)(legacy_path, target_path) | One-time copy of a legacy store into the canonical root.                     |
| [`read_json_file`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.read_json_file)(path)                     | Read a JSON file, or return `None` if it does not exist.                     |
| [`read_text_file`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.read_text_file)(path)                     | Read a text file, or return `None` if it does not exist.                     |
| [`user_base`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.user_base)([user, root])                  | Filesystem base for a candidate: `<root>` or `<data>/users/<user>`.          |
| [`write_json_file`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.write_json_file)(path, obj)               | Write `obj` as indented JSON, creating parent dirs as needed.                |
| [`write_text_file`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.write_text_file)(path, text)              | Write `text` to a file, creating parent dirs as needed.                      |

### Classes

| [`JDStore`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.JDStore)(user, jd_id, \*[, root])   | Per-engagement storage under `users/<user>/jds/<jd_id>/`.              |
|-------------------------------------------------------------------------------------|------------------------------------------------------------------------|
| [`UserStore`](_autosummary/hired.persistence.base.html.md#hired.persistence.base.UserStore)([user, root])            | Per-candidate cross-JD storage: raw sources + agent-maintained `info`. |

### hired.persistence.base.BytesStore

A store of raw `bytes`, keyed by real filenames.

alias of [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`bytes`](https://docs.python.org/3/builtins/stdtypes.html#bytes)]

### *class* hired.persistence.base.JDStore(user, jd_id, , root=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Per-engagement storage under `users/<user>/jds/<jd_id>/`.

An engagement is one *or a group of* related JDs of the same company; it
holds the parsed jobs, alignment reports (+ archived history), company
research, and interview-prep briefings for that company’s role(s).

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> jd = JDStore('me', 'acme')
>>> jd.reports['role-1'] = {'verdict': {'recommendation': 'apply'}}
>>> jd.reports['role-1']['verdict']['recommendation']
'apply'
>>> jd.write_meta({'company': 'Acme'})
>>> jd.read_meta()['company']
'Acme'
```

### hired.persistence.base.JsonStore

A store of JSON-able values (dicts in Python, JSON on disk), keyed by bare ids.

alias of [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### hired.persistence.base.TextStore

A store of `str` values (e.g. markdown files), keyed by bare names.

alias of [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### *class* hired.persistence.base.UserStore(user='me', , root=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Per-candidate cross-JD storage: raw sources + agent-maintained `info`.

`raw` is a bytes store; `facts` and `qa` are json stores; `synopsis`
is a single markdown file accessed via `read_synopsis()` /
`write_synopsis()`.

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> us = UserStore()                       # default user "me"
>>> us.facts['f1'] = {'statement': 'knows Python'}
>>> us.facts['f1']
{'statement': 'knows Python'}
>>> us.raw['cv.pdf'] = b'%PDF-1.4'
>>> us.raw['cv.pdf']
b'%PDF-1.4'
>>> us.write_synopsis('# me')
>>> us.read_synopsis()
'# me'
```

### hired.persistence.base.app_data_dir(\*subpaths, make=True)

Return the canonical hired data directory, joined with `subpaths`.

The directory is created when `make` is true (the default).

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> import os, tempfile
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> root = app_data_dir()
>>> os.path.isdir(root)
True
>>> app_data_dir('users', 'me').endswith(os.path.join('users', 'me'))
True
```

### hired.persistence.base.bytes_store(rootdir)

A `MutableMapping` of raw `bytes`; keys are real filenames (extension kept).

* **Return type:**
  [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`bytes`](https://docs.python.org/3/builtins/stdtypes.html#bytes)]

### hired.persistence.base.json_store(rootdir)

A `MutableMapping` of JSON-able values: bare-id keys, `<id>.json` files.

Built on `JsonFiles` (dict↔JSON value codec) + a `.json` key codec. Missing
intermediate directories are created on write, so nested keys (e.g. `"job/stamp"`)
work transparently.

* **Return type:**
  [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### hired.persistence.base.list_jds(user='me', , root=None)

Engagement ids under `users/<user>/jds/` (sorted; empty if none).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### hired.persistence.base.markdown_store(rootdir)

A `MutableMapping` of `str` values: bare keys, `<key>.md` files.

* **Return type:**
  [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### hired.persistence.base.migrate_legacy(legacy_path, target_path)

One-time copy of a legacy store into the canonical root.

If `target_path` does not yet exist but `legacy_path` does, copy it
(file or directory) so historical data is preserved when storage roots are
unified. No-op otherwise. Returns True iff a copy happened.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.persistence.base.read_json_file(path)

Read a JSON file, or return `None` if it does not exist.

* **Return type:**
  [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)

### hired.persistence.base.read_text_file(path)

Read a text file, or return `None` if it does not exist.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None)

### hired.persistence.base.user_base(user='me', , root=None)

Filesystem base for a candidate: `<root>` or `<data>/users/<user>`.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### hired.persistence.base.write_json_file(path, obj)

Write `obj` as indented JSON, creating parent dirs as needed.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### hired.persistence.base.write_text_file(path, text)

Write `text` to a file, creating parent dirs as needed.

Uses `newline=""` so stored files keep `\n` verbatim on every platform
(no `\r\n` translation on Windows), keeping the data store consistent.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)


# _autosummary/hired.persistence.html.md

# hired.persistence

dol-based persistence foundation for hired (Storage v2).

All hired persistence lives **outside the repository** under a single canonical
data root (`~/.local/share/hired/` by default, overridable via `HIRED_DATA_DIR`).
Stores are `MutableMapping` views over the filesystem (via `dol`) with
filesystem codecs that keep keys extension-less while writing properly-extensioned
files. Per-candidate data is split two levels deep: a cross-JD `user/` subtree
([`UserStore`](_autosummary/hired.persistence.html.md#hired.persistence.UserStore)) and per-engagement `jds/<jd_id>/` subtrees ([`JDStore`](_autosummary/hired.persistence.html.md#hired.persistence.JDStore)).

See `misc/docs/DESIGN.md` §4 for the full layout and rationale.

### Functions

| [`app_data_dir`](_autosummary/hired.persistence.html.md#hired.persistence.app_data_dir)(\*subpaths[, make])                  | Return the canonical hired data directory, joined with `subpaths`.           |
|----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
| [`user_base`](_autosummary/hired.persistence.html.md#hired.persistence.user_base)([user, root])                           | Filesystem base for a candidate: `<root>` or `<data>/users/<user>`.          |
| [`list_jds`](_autosummary/hired.persistence.html.md#hired.persistence.list_jds)([user, root])                            | Engagement ids under `users/<user>/jds/` (sorted; empty if none).            |
| [`json_store`](_autosummary/hired.persistence.html.md#hired.persistence.json_store)(rootdir)                               | A `MutableMapping` of JSON-able values: bare-id keys, `<id>.json` files.     |
| [`markdown_store`](_autosummary/hired.persistence.html.md#hired.persistence.markdown_store)(rootdir)                           | A `MutableMapping` of `str` values: bare keys, `<key>.md` files.             |
| [`bytes_store`](_autosummary/hired.persistence.html.md#hired.persistence.bytes_store)(rootdir)                              | A `MutableMapping` of raw `bytes`; keys are real filenames (extension kept). |
| [`migrate_legacy`](_autosummary/hired.persistence.html.md#hired.persistence.migrate_legacy)(legacy_path, target_path)          | One-time copy of a legacy store into the canonical root.                     |
| [`ensure_v2`](_autosummary/hired.persistence.html.md#hired.persistence.ensure_v2)([user, root])                           | Migrate the user to v2 if a legacy layout is detected.                       |
| [`is_legacy_layout`](_autosummary/hired.persistence.html.md#hired.persistence.is_legacy_layout)([user, root])                    | True iff any legacy v1 flat directory remains for this user.                 |
| [`migrate_user_to_v2`](_autosummary/hired.persistence.html.md#hired.persistence.migrate_user_to_v2)([user, root, company_of, ...]) | Migrate one user's flat v1 data to the v2 layout.                            |

### Classes

| [`UserStore`](_autosummary/hired.persistence.html.md#hired.persistence.UserStore)([user, root])          | Per-candidate cross-JD storage: raw sources + agent-maintained `info`.   |
|-----------------------------------------------------------------------------------|--------------------------------------------------------------------------|
| [`JDStore`](_autosummary/hired.persistence.html.md#hired.persistence.JDStore)(user, jd_id, \*[, root]) | Per-engagement storage under `users/<user>/jds/<jd_id>/`.                |
| [`Repository`](_autosummary/hired.persistence.html.md#hired.persistence.Repository)(store, \*[, model])   | Validated CRUD over a `MutableMapping` for a single pydantic model type. |

### *class* hired.persistence.JDStore(user, jd_id, , root=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Per-engagement storage under `users/<user>/jds/<jd_id>/`.

An engagement is one *or a group of* related JDs of the same company; it
holds the parsed jobs, alignment reports (+ archived history), company
research, and interview-prep briefings for that company’s role(s).

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> jd = JDStore('me', 'acme')
>>> jd.reports['role-1'] = {'verdict': {'recommendation': 'apply'}}
>>> jd.reports['role-1']['verdict']['recommendation']
'apply'
>>> jd.write_meta({'company': 'Acme'})
>>> jd.read_meta()['company']
'Acme'
```

### *class* hired.persistence.Repository(store, , model=None)

Bases: [`Generic`](https://docs.python.org/3/library/typing.html#typing.Generic)[`M`]

Validated CRUD over a `MutableMapping` for a single pydantic model type.

Subclasses set `model` and [`key_of()`](_autosummary/hired.persistence.html.md#hired.persistence.Repository.key_of). The store holds plain
JSON-able dicts; models are validated on the way in and out.

#### key_of(item)

Derive the storage key for an item (defaults to its `id` field).

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### *class* hired.persistence.UserStore(user='me', , root=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Per-candidate cross-JD storage: raw sources + agent-maintained `info`.

`raw` is a bytes store; `facts` and `qa` are json stores; `synopsis`
is a single markdown file accessed via `read_synopsis()` /
`write_synopsis()`.

```pycon
>>> import tempfile, os
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> us = UserStore()                       # default user "me"
>>> us.facts['f1'] = {'statement': 'knows Python'}
>>> us.facts['f1']
{'statement': 'knows Python'}
>>> us.raw['cv.pdf'] = b'%PDF-1.4'
>>> us.raw['cv.pdf']
b'%PDF-1.4'
>>> us.write_synopsis('# me')
>>> us.read_synopsis()
'# me'
```

### hired.persistence.app_data_dir(\*subpaths, make=True)

Return the canonical hired data directory, joined with `subpaths`.

The directory is created when `make` is true (the default).

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> import os, tempfile
>>> os.environ['HIRED_DATA_DIR'] = tempfile.mkdtemp()
>>> root = app_data_dir()
>>> os.path.isdir(root)
True
>>> app_data_dir('users', 'me').endswith(os.path.join('users', 'me'))
True
```

### hired.persistence.bytes_store(rootdir)

A `MutableMapping` of raw `bytes`; keys are real filenames (extension kept).

* **Return type:**
  [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`bytes`](https://docs.python.org/3/builtins/stdtypes.html#bytes)]

### hired.persistence.ensure_v2(user='me', , root=None)

Migrate the user to v2 if a legacy layout is detected. Returns True if migrated.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.persistence.is_legacy_layout(user='me', , root=None)

True iff any legacy v1 flat directory remains for this user.

Gated on the *presence of legacy dirs*, not on the existence of `user/` — a
fully-migrated user has had its legacy dirs removed, so this returns False;
a partially-migrated (interrupted) user still has some, so a re-run resumes.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.persistence.json_store(rootdir)

A `MutableMapping` of JSON-able values: bare-id keys, `<id>.json` files.

Built on `JsonFiles` (dict↔JSON value codec) + a `.json` key codec. Missing
intermediate directories are created on write, so nested keys (e.g. `"job/stamp"`)
work transparently.

* **Return type:**
  [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### hired.persistence.list_jds(user='me', , root=None)

Engagement ids under `users/<user>/jds/` (sorted; empty if none).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### hired.persistence.markdown_store(rootdir)

A `MutableMapping` of `str` values: bare keys, `<key>.md` files.

* **Return type:**
  [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### hired.persistence.migrate_legacy(legacy_path, target_path)

One-time copy of a legacy store into the canonical root.

If `target_path` does not yet exist but `legacy_path` does, copy it
(file or directory) so historical data is preserved when storage roots are
unified. No-op otherwise. Returns True iff a copy happened.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.persistence.migrate_user_to_v2(user='me', , root=None, company_of=None, dry_run=False)

Migrate one user’s flat v1 data to the v2 layout. Returns the move plan.

Idempotent: a no-op (empty plan) if the user is already on v2 or has no
legacy data. With `dry_run=True` nothing is moved — the returned
`[(src, dst), ...]` plan can be inspected first.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]

### hired.persistence.user_base(user='me', , root=None)

Filesystem base for a candidate: `<root>` or `<data>/users/<user>`.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### Modules

| [`base`](_autosummary/hired.persistence.base.html.md#module-hired.persistence.base)             | Canonical data root, filesystem codecs, and the two-level candidate layout.     |
|-------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
| [`migrate`](_autosummary/hired.persistence.migrate.html.md#module-hired.persistence.migrate)       | One-time migration of legacy flat per-user data to the Storage v2 layout.       |
| [`repository`](_autosummary/hired.persistence.repository.html.md#module-hired.persistence.repository) | A small repository base that maps validated domain models to a key-value store. |


# _autosummary/hired.persistence.migrate.html.md

# hired.persistence.migrate

One-time migration of legacy flat per-user data to the Storage v2 layout.

Storage v1 kept every store kind flat under `users/<user>/<kind>/` with
*extension-less* files. Storage v2 (see [`hired.persistence.base`](_autosummary/hired.persistence.base.html.md#module-hired.persistence.base)) splits the
data into a cross-JD `user/` subtree and per-engagement `jds/<jd_id>/`
subtrees, and gives every file a proper extension.

This module moves the data once, idempotently:

- `facts/` `qa/`           → `user/info/<kind>/<name>.json`
- `uploads/`                 → `user/raw/<name>`        (filename kept)
- `synopsis/synopsis.md`     → `user/info/synopsis.md`
- `jobs/` `reports/` `report_history/` `company/` `interview_prep/`
  : → `jds/<jd_id>/<kind>/<rel>.json`

Engagements are grouped by company **when company research seeds the slugs**: if a
`company/<slug>` entry exists (or a prior partial run already created
`jds/<slug>/`), all items whose key equals `<slug>` or starts with `<slug>-`
land in that company’s single workspace (so a company’s several role reports + its
shared research + prep stay together). Without any such seed, each top-level key
becomes its own engagement; pass a custom `company_of` to force grouping.

The migration is **resumable**: it is gated on “any legacy directory remains”, moves
files individually, refuses to overwrite an existing destination, and removes the
empty legacy directories only after every move succeeds. So an interrupted run
(crash, disk-full) is simply re-run — already-moved files are skipped and the
remaining ones complete. The *intelligence* of the package is unaffected — this is
deterministic file plumbing, run automatically via [`ensure_v2()`](_autosummary/hired.persistence.migrate.html.md#hired.persistence.migrate.ensure_v2) on first v2
access, or explicitly (with [`migrate_user_to_v2()`](_autosummary/hired.persistence.migrate.html.md#hired.persistence.migrate.migrate_user_to_v2), optionally `dry_run=True`).

### Functions

| [`ensure_v2`](_autosummary/hired.persistence.migrate.html.md#hired.persistence.migrate.ensure_v2)([user, root])                           | Migrate the user to v2 if a legacy layout is detected.       |
|----------------------------------------------------------------------------------------------------|--------------------------------------------------------------|
| [`is_legacy_layout`](_autosummary/hired.persistence.migrate.html.md#hired.persistence.migrate.is_legacy_layout)([user, root])                    | True iff any legacy v1 flat directory remains for this user. |
| [`migrate_user_to_v2`](_autosummary/hired.persistence.migrate.html.md#hired.persistence.migrate.migrate_user_to_v2)([user, root, company_of, ...]) | Migrate one user's flat v1 data to the v2 layout.            |

### hired.persistence.migrate.ensure_v2(user='me', , root=None)

Migrate the user to v2 if a legacy layout is detected. Returns True if migrated.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.persistence.migrate.is_legacy_layout(user='me', , root=None)

True iff any legacy v1 flat directory remains for this user.

Gated on the *presence of legacy dirs*, not on the existence of `user/` — a
fully-migrated user has had its legacy dirs removed, so this returns False;
a partially-migrated (interrupted) user still has some, so a re-run resumes.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### hired.persistence.migrate.migrate_user_to_v2(user='me', , root=None, company_of=None, dry_run=False)

Migrate one user’s flat v1 data to the v2 layout. Returns the move plan.

Idempotent: a no-op (empty plan) if the user is already on v2 or has no
legacy data. With `dry_run=True` nothing is moved — the returned
`[(src, dst), ...]` plan can be inspected first.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]


# _autosummary/hired.persistence.repository.html.md

# hired.persistence.repository

A small repository base that maps validated domain models to a key-value store.

A [`Repository`](_autosummary/hired.persistence.repository.html.md#hired.persistence.repository.Repository) wraps any `MutableMapping` (typically a `dol` file
store from [`hired.persistence.base`](_autosummary/hired.persistence.base.html.md#module-hired.persistence.base)) and a pydantic model class, handling
(de)serialization and validation so domain code deals in models, not dicts.

### Classes

| [`Repository`](_autosummary/hired.persistence.repository.html.md#hired.persistence.repository.Repository)(store, \*[, model])   | Validated CRUD over a `MutableMapping` for a single pydantic model type.   |
|-----------------------------------------------------------------------------------|----------------------------------------------------------------------------|

### *class* hired.persistence.repository.Repository(store, , model=None)

Bases: [`Generic`](https://docs.python.org/3/library/typing.html#typing.Generic)[`M`]

Validated CRUD over a `MutableMapping` for a single pydantic model type.

Subclasses set `model` and [`key_of()`](_autosummary/hired.persistence.repository.html.md#hired.persistence.repository.Repository.key_of). The store holds plain
JSON-able dicts; models are validated on the way in and out.

#### key_of(item)

Derive the storage key for an item (defaults to its `id` field).

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)


# _autosummary/hired.render.html.md

# hired.render

Rendering pipeline and theme management.

Current features:

* Pluggable renderer system supporting multiple backends.
* HTML and PDF rendering via HTMLRenderer
* Optional RenderCV integration for high-quality PDF generation


# _autosummary/hired.renderers.html.html.md

# hired.renderers.html

HTML renderer implementation using Jinja2 templates.

### Functions

| [`html_to_pdf`](_autosummary/hired.renderers.html.html.md#hired.renderers.html.html_to_pdf)(html, css)   | Convert HTML to PDF using WeasyPrint if available, else minimal builder.   |
|---------------------------------------------------------------------------|----------------------------------------------------------------------------|

### Classes

| [`ThemeRegistry`](_autosummary/hired.renderers.html.html.md#hired.renderers.html.ThemeRegistry)(\*[, themes_path])   | Registry for available themes.   |
|-------------------------------------------------------------------------------------|----------------------------------|
| [`HTMLRenderer`](_autosummary/hired.renderers.html.html.md#hired.renderers.html.HTMLRenderer)(\*[, theme_registry]) | Renders resume to HTML or PDF.   |

### *class* hired.renderers.html.HTMLRenderer(, theme_registry=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Renders resume to HTML or PDF.

Process:

> * Build a sanitized context (omit empty sections).
> * Render via Jinja2 template.
> * If PDF: use WeasyPrint if available, else fallback minimal PDF builder.

### *class* hired.renderers.html.ThemeRegistry(, themes_path=None)

Bases: [`Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]

Registry for available themes.

Each theme is a mapping with keys:
: name: str
  template: str (filename relative to themes directory)
  css: str (raw CSS text, optional)

### hired.renderers.html.html_to_pdf(html, css)

Convert HTML to PDF using WeasyPrint if available, else minimal builder.

* **Return type:**
  [`bytes`](https://docs.python.org/3/builtins/stdtypes.html#bytes)


# _autosummary/hired.renderers.html.md

# hired.renderers

Renderer implementations package.
Contains various renderer backends for different output formats.

### Classes

| [`HTMLRenderer`](_autosummary/hired.renderers.html.md#hired.renderers.HTMLRenderer)(\*[, theme_registry])    | Renders resume to HTML or PDF.                               |
|----------------------------------------------------------------------------------------|--------------------------------------------------------------|
| [`RenderCVRenderer`](_autosummary/hired.renderers.html.md#hired.renderers.RenderCVRenderer)([strict_validation]) | Renderer that uses RenderCV for high-quality PDF generation. |

### *class* hired.renderers.HTMLRenderer(, theme_registry=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Renders resume to HTML or PDF.

Process:

> * Build a sanitized context (omit empty sections).
> * Render via Jinja2 template.
> * If PDF: use WeasyPrint if available, else fallback minimal PDF builder.

### *class* hired.renderers.RenderCVRenderer(strict_validation=False)

Bases: [`Renderer`](_autosummary/hired.base.html.md#hired.base.Renderer)

Renderer that uses RenderCV for high-quality PDF generation.

This renderer:

1. Converts JSON Resume format to RenderCV YAML format
2. Uses RenderCV to generate PDF with LaTeX/Typst backend
3. Returns the rendered PDF bytes

Features robust data handling:

- Fills in missing required fields with sensible defaults
- Issues warnings about missing or incomplete data
- Gracefully handles schema validation issues

#### render(content, config)

Render resume content using RenderCV backend.

* **Return type:**
  [`bytes`](https://docs.python.org/3/builtins/stdtypes.html#bytes)

### Modules

| [`html`](_autosummary/hired.renderers.html.html.md#module-hired.renderers.html)         | HTML renderer implementation using Jinja2 templates.         |
|-------------------------------------------------------------------------------------------|--------------------------------------------------------------|
| [`rendercv`](_autosummary/hired.renderers.rendercv.html.md#module-hired.renderers.rendercv) | RenderCV renderer implementation using the RenderCV backend. |


# _autosummary/hired.renderers.rendercv.html.md

# hired.renderers.rendercv

RenderCV renderer implementation using the RenderCV backend.

### Classes

| [`RenderCVRenderer`](_autosummary/hired.renderers.rendercv.html.md#hired.renderers.rendercv.RenderCVRenderer)([strict_validation])   | Renderer that uses RenderCV for high-quality PDF generation.   |
|------------------------------------------------------------------------------------------|----------------------------------------------------------------|

### *class* hired.renderers.rendercv.RenderCVRenderer(strict_validation=False)

Bases: [`Renderer`](_autosummary/hired.base.html.md#hired.base.Renderer)

Renderer that uses RenderCV for high-quality PDF generation.

This renderer:

1. Converts JSON Resume format to RenderCV YAML format
2. Uses RenderCV to generate PDF with LaTeX/Typst backend
3. Returns the rendered PDF bytes

Features robust data handling:

- Fills in missing required fields with sensible defaults
- Issues warnings about missing or incomplete data
- Gracefully handles schema validation issues

#### render(content, config)

Render resume content using RenderCV backend.

* **Return type:**
  [`bytes`](https://docs.python.org/3/builtins/stdtypes.html#bytes)


# _autosummary/hired.resume_agent.html.md

# hired.resume_agent

Resume Generation System - Core Architecture

A hybrid LangChain/DSPy system for AI-powered resume creation with manual
and autonomous operation modes.

Architecture follows supervisor-worker pattern with:

- ResumeSession: Stateful conversation manager for manual mode
- ResumeExpertAgent: Autonomous controller using ResumeSession as a tool
- Specialized worker agents: expansion, distillation, matching, search

### Classes

| [`ConversationMemory`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ConversationMemory)(\*[, max_recent_turns])         | Manages conversation history with tiered memory strategy.                   |
|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
| [`DistillationAgent`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.DistillationAgent)(\*[, llm_config])                | Distills verbose text into concise, impactful statements.                   |
| [`ExpansionAgent`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ExpansionAgent)(\*[, llm_config])                   | Expands brief bullet points into detailed achievement descriptions.         |
| [`LLMConfig`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.LLMConfig)(model[, temperature, max_tokens, ...])   | Configuration for LLM model selection and parameters.                       |
| [`LLMProvider`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.LLMProvider)(\*args, \*\*kwargs)                    | Protocol for LLM execution.                                                 |
| [`MatchingAgent`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.MatchingAgent)(\*[, llm_config])                    | Performs semantic matching between candidate info and job requirements.     |
| [`ModelRegistry`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ModelRegistry)(supervisor, workers[, ...])          | Registry for different model configurations by role.                        |
| [`OperationMode`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.OperationMode)(\*values)                            | Session operation mode.                                                     |
| [`Plan`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Plan)(steps, rationale[, created_at])               | Structured execution plan for resume creation.                              |
| [`PlanStep`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.PlanStep)(id, action, description[, params, ...])   | A single step in an execution plan.                                         |
| [`ResumeExpertAgent`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ResumeExpertAgent)(\*[, llm_config, ...])           | Autonomous agent that uses ResumeSession as a tool.                         |
| [`ResumeSession`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ResumeSession)(job_info, candidate_info, \*[, ...]) | Stateful conversation session for resume creation.                          |
| [`SearchAgent`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.SearchAgent)(\*[, llm_config])                      | Performs web searches to expand context about companies, technologies, etc. |
| [`SessionSnapshot`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.SessionSnapshot)(turn_count, data, mode[, ...])     | Immutable snapshot of session state at a point in time.                     |
| [`SessionState`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.SessionState)()                                     | Structured state for resume creation session.                               |
| [`SessionStore`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.SessionStore)(\*[, data_dir])                       | Manages automatic persistence of resume sessions.                           |
| [`Turn`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Turn)(role, content[, timestamp, metadata])         | A single conversation turn.                                                 |

### *class* hired.resume_agent.ConversationMemory(, max_recent_turns=10)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Manages conversation history with tiered memory strategy.

Minimal docstring: Stores and retrieves conversation turns with summarization.

#### add_turn(role, content, \*\*metadata)

Add a conversation turn.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### get_all_turns()

Get all conversation turns.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`Turn`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Turn)]

#### get_context_for_prompt()

Generate context for LLM prompt with recent history.

Yields dicts with ‘role’ and ‘content’ for LLM consumption.

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]

#### get_recent_turns(n=None)

Get the n most recent turns (defaults to max_recent_turns).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`Turn`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Turn)]

#### summarize_old_turns()

Placeholder for summarization of old history.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.resume_agent.DistillationAgent(, llm_config=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Distills verbose text into concise, impactful statements.

Uses DSPy-optimized prompts with metrics for conciseness and clarity.

#### distill(verbose_text, , max_words=None, preserve_metrics=True)

Distill verbose text into concise statement.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> config = LLMConfig(model="gpt-4")
>>> agent = DistillationAgent(llm_config=config)
>>> agent.llm_config.model
'gpt-4'
```

### *class* hired.resume_agent.ExpansionAgent(, llm_config=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Expands brief bullet points into detailed achievement descriptions.

Uses DSPy-optimized prompts for consistent, high-quality expansions.

#### expand(brief_text, context, , target_length='detailed')

Expand brief text into detailed description.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> config = LLMConfig(model="gpt-4")
>>> agent = ExpansionAgent(llm_config=config)
>>> agent.llm_config.model
'gpt-4'
```

### *class* hired.resume_agent.LLMConfig(model, temperature=0.7, max_tokens=None, top_p=1.0, provider='openai', api_key=None, base_url=None, extra_params=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Configuration for LLM model selection and parameters.

```pycon
>>> config = LLMConfig(model="gpt-4", temperature=0.7)
>>> config.model
'gpt-4'
```

#### to_dspy_lm()

Convert to DSPy LM instance.

* **Return type:**
  [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)

#### to_langchain_kwargs()

Convert to LangChain model kwargs.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.resume_agent.LLMProvider(\*args, \*\*kwargs)

Bases: [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol)

Protocol for LLM execution.

#### chat(messages, \*\*kwargs)

Generate response for chat messages.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### complete(prompt, \*\*kwargs)

Generate completion for prompt.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### *class* hired.resume_agent.MatchingAgent(, llm_config=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Performs semantic matching between candidate info and job requirements.

Uses embedding-based similarity and cross-encoder reranking.

#### find_matches(candidate_text, job_requirements)

Find semantic matches between candidate experience and job needs.

Yields dicts with ‘candidate_snippet’, ‘job_requirement’, ‘score’.

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]

### *class* hired.resume_agent.ModelRegistry(supervisor, workers, expansion=None, distillation=None, matching=None, search=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Registry for different model configurations by role.

Enables cost optimization by using different models for different tasks.

```pycon
>>> registry = ModelRegistry(
...     supervisor=LLMConfig("gpt-4"),
...     workers=LLMConfig("gpt-3.5-turbo")
... )
>>> registry.supervisor.model
'gpt-4'
```

#### *classmethod* default()

Create default registry with sensible model choices.

* **Return type:**
  [`ModelRegistry`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ModelRegistry)

#### *classmethod* fast()

Create registry optimized for speed/cost.

* **Return type:**
  [`ModelRegistry`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ModelRegistry)

#### get_config(role)

Get model config for specific role.

Falls back to workers config if role-specific config not set.

* **Return type:**
  [`LLMConfig`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.LLMConfig)

#### *classmethod* quality()

Create registry optimized for quality.

* **Return type:**
  [`ModelRegistry`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ModelRegistry)

### *class* hired.resume_agent.OperationMode(\*values)

Bases: [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Session operation mode.

### *class* hired.resume_agent.Plan(steps, rationale, created_at=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Structured execution plan for resume creation.

#### get_executable_steps(completed_steps)

Get steps that can currently be executed.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`PlanStep`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.PlanStep)]

#### to_markdown()

Convert plan to human-readable markdown.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### validate()

Validate plan structure and dependencies.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### *class* hired.resume_agent.PlanStep(id, action, description, params=<factory>, dependencies=<factory>, estimated_tokens=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A single step in an execution plan.

#### can_execute(completed_steps)

Check if all dependencies are satisfied.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### *class* hired.resume_agent.ResumeExpertAgent(, llm_config=None, model_registry=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Autonomous agent that uses ResumeSession as a tool.

Operates in auto mode, making decisions about expansion, distillation,
search, and generation operations to produce complete resumes.

```pycon
>>> config = LLMConfig(model="gpt-4")
>>> agent = ResumeExpertAgent(llm_config=config)
>>> agent.llm_config.model
'gpt-4'
```

#### create_resume(session, , mode='standard', max_iterations=5)

Autonomously create resume using session as tool.

Operates in plan-and-execute pattern:

1. Analyze job and candidate info
2. Plan resume creation strategy
3. Execute operations (expand, distill, match)
4. Generate resume
5. Critique and refine

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### execute_plan(session, plan, , interactive=False, approval_callback=None)

Execute a plan step by step.

* **Parameters:**
  * **session** ([`ResumeSession`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ResumeSession)) – Resume session to operate on
  * **plan** ([`Plan`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Plan)) – Plan to execute
  * **interactive** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – If True, pause after each step for approval
* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dict with execution results and final outputs

#### propose_plan(session, , mode='standard')

Generate execution plan for resume creation.

Returns structured Plan object that can be edited before execution.

* **Return type:**
  [`Plan`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Plan)

#### revise_plan(plan, instruction)

Revise plan based on natural language instruction.

Uses LLM to interpret instruction and modify plan accordingly.

* **Return type:**
  [`Plan`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Plan)

### *class* hired.resume_agent.ResumeSession(job_info, candidate_info, , mode=OperationMode.MANUAL, system_prompt=None, max_recent_turns=10, llm_config=None, model_registry=None, auto_persist=True, data_dir=None, name=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Stateful conversation session for resume creation.

Provides manual chat interface where users give natural language
instructions to perform expansion, distillation, search, and generation
operations. Maintains conversation history and structured state.

```pycon
>>> config = LLMConfig("gpt-4")
>>> session = ResumeSession(
...     job_info="Senior ML Engineer at TechCo",
...     candidate_info="5 years Python, ML experience",
...     llm_config=config
... )
>>> session.llm_config.model
'gpt-4'
```

#### chat(user_message)

Process user instruction and return assistant response.

This is the main interface for manual mode operation.
Automatically persists session after each turn if auto_persist enabled.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### *property* history *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[Turn](_autosummary/hired.resume_agent.html.md#hired.resume_agent.Turn)]*

Get all conversation turns.

#### *classmethod* list_persisted(data_dir=None)

List all persisted sessions.

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]

```pycon
>>> for session_info in ResumeSession.list_persisted():
...     print(session_info['session_id'])
```

#### *classmethod* load(session_id, , data_dir=None, llm_config=None)

Load session from persistent storage.

* **Return type:**
  [`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`ResumeSession`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ResumeSession)]

```pycon
>>> session = ResumeSession.load("abc123def456")
>>> session.session_id if session else None
'abc123def456'
```

#### *property* metadata *: [dict](https://docs.python.org/3/builtins/stdtypes.html#dict)[[str](https://docs.python.org/3/builtins/stdtypes.html#str), [Any](https://docs.python.org/3/library/typing.html#typing.Any)]*

Return a small metadata dict for quick inspection.

Includes: session_id, name, created_at (iso), n_turns, mode, model

#### save(data_dir=None)

Manually save session to persistent storage.

Returns path to saved session file.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

#### *property* snapshots *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[SessionSnapshot](_autosummary/hired.resume_agent.html.md#hired.resume_agent.SessionSnapshot)]*

Get all session snapshots.

#### *property* state *: [SessionState](_autosummary/hired.resume_agent.html.md#hired.resume_agent.SessionState)*

Get current session state.

#### switch_mode(mode)

Switch between manual and auto operation modes.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.resume_agent.SearchAgent(, llm_config=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Performs web searches to expand context about companies, technologies, etc.

Integrates with search APIs to gather relevant information.

#### search(query, , result_count=5)

Search web for relevant information.

Yields dicts with ‘title’, ‘snippet’, ‘url’.

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]

### *class* hired.resume_agent.SessionSnapshot(turn_count, data, mode, timestamp=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Immutable snapshot of session state at a point in time.

```pycon
>>> snapshot = SessionSnapshot(turn_count=5, data={'skills': ['Python']})
>>> snapshot.turn_count
5
```

### *class* hired.resume_agent.SessionState

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Structured state for resume creation session.

Stores extracted entities, analysis results, and work-in-progress content.

#### get(key, default=None)

Get state value with default.

* **Return type:**
  [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)

#### snapshot()

Create immutable snapshot of current state.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

#### update(updates)

Update state with new information.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.resume_agent.SessionStore(, data_dir=None)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

Manages automatic persistence of resume sessions.

Sessions are saved after each chat turn to enable recovery and history.

```pycon
>>> store = SessionStore()
>>> store.data_dir.name
'resume_agent_sessions'
```

#### add(session)

Alias for save_session to behave like a set.add(session).

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

#### delete_session(session_id)

Delete session from persistent storage.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

#### list_sessions()

List all persisted sessions.

Yields session metadata dicts.

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]

#### load_session(session_id, , llm_config=None)

Load session from persistent storage.

Returns None if session not found.

* **Return type:**
  [`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`ResumeSession`](_autosummary/hired.resume_agent.html.md#hired.resume_agent.ResumeSession)]

#### save_session(session)

Save session to persistent storage.

Returns path to saved session file.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

### *class* hired.resume_agent.Turn(role, content, timestamp=<factory>, metadata=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A single conversation turn.

```pycon
>>> turn = Turn(role="user", content="Make a resume")
>>> turn.role
'user'
```


# _autosummary/hired.resumejson_pydantic_models.html.md

# hired.resumejson_pydantic_models

Pydantic models for resume json schema

### Classes

| [`Award`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Award)(\*\*data)         |    |
|--------------------------------------------------------------------------|----|
| [`Basics`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Basics)(\*\*data)        |    |
| [`Certificate`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Certificate)(\*\*data)   |    |
| [`EducationItem`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.EducationItem)(\*\*data) |    |
| [`Interest`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Interest)(\*\*data)      |    |
| [`Iso8601`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Iso8601)([root])         |    |
| [`Language`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Language)(\*\*data)      |    |
| [`Location`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Location)(\*\*data)      |    |
| [`Meta`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Meta)(\*\*data)          |    |
| [`Profile`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Profile)(\*\*data)       |    |
| [`Project`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Project)(\*\*data)       |    |
| [`Publication`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Publication)(\*\*data)   |    |
| [`Reference`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Reference)(\*\*data)     |    |
| [`ResumeSchema`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.ResumeSchema)(\*\*data)  |    |
| [`Skill`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.Skill)(\*\*data)         |    |
| [`VolunteerItem`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.VolunteerItem)(\*\*data) |    |
| [`WorkItem`](_autosummary/hired.resumejson_pydantic_models.html.md#hired.resumejson_pydantic_models.WorkItem)(\*\*data)      |    |

### *class* hired.resumejson_pydantic_models.Award(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Basics(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Certificate(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.EducationItem(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Interest(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Iso8601(root=PydanticUndefined, \*\*data)

Bases: `RootModel[Annotated[str, StringConstraints]]`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Language(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Location(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Meta(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Profile(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Project(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Publication(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Reference(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.ResumeSchema(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'forbid'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.Skill(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.VolunteerItem(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].

### *class* hired.resumejson_pydantic_models.WorkItem(\*\*data)

Bases: `BaseModel`

#### model_config *: [ClassVar](https://docs.python.org/3/library/typing.html#typing.ClassVar)[ConfigDict]* *= {'extra': 'allow'}*

Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict].


# _autosummary/hired.search.base.html.md

# hired.search.base

Base classes and interfaces for job search functionality.

### Classes

| [`CompensationInfo`](_autosummary/hired.search.base.html.md#hired.search.base.CompensationInfo)([min_amount, max_amount, ...])   | Compensation information for a job.              |
|----------------------------------------------------------------------------------------------------|--------------------------------------------------|
| [`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)(title, source[, company, ...])          | Standardized job result across all sources.      |
| [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)()                                 | Abstract base class for job search sources.      |
| [`JobType`](_autosummary/hired.search.base.html.md#hired.search.base.JobType)(\*values)                                 | Standardized job types across all sources.       |
| [`LocationInfo`](_autosummary/hired.search.base.html.md#hired.search.base.LocationInfo)([city, state, country, ...])         | Location information for a job.                  |
| [`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)(query[, location, country, ...])   | Standardized search criteria across all sources. |

### Exceptions

| [`SourceConfigError`](_autosummary/hired.search.base.html.md#hired.search.base.SourceConfigError)   | Raised when a source is not properly configured.   |
|----------------------------------------------------------------------|----------------------------------------------------|

### *class* hired.search.base.CompensationInfo(min_amount=None, max_amount=None, currency=None, interval=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Compensation information for a job.

### *class* hired.search.base.JobResult(title, source, company=None, company_url=None, job_url=None, location=None, is_remote=None, description=None, job_type=None, compensation=None, date_posted=None, date_updated=None, application_deadline=None, skills=<factory>, benefits=<factory>, emails=<factory>, raw_data=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Standardized job result across all sources.

This provides a unified interface regardless of which source
the job was retrieved from.

#### to_dict()

Convert JobResult to dictionary.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.search.base.JobSearchSource

Bases: [`ABC`](https://docs.python.org/3/library/abc.html#abc.ABC)

Abstract base class for job search sources.

All job search sources must implement this interface to be
registered in the system.

#### *abstract property* display_name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the display name of this source (e.g., ‘Indeed’, ‘USAJobs’).

#### *abstractmethod* get_setup_instructions()

Return setup instructions for this source.

Should include:

- Where to get API keys if needed
- Environment variables or config file settings
- URLs for documentation

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Multi-line string with setup instructions.

#### *abstractmethod* is_configured()

Check if this source is properly configured.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if the source is ready to use, False otherwise.

#### *abstract property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the name of this source (e.g., ‘indeed’, ‘usajobs’).

#### *abstract property* requires_auth *: [bool](https://docs.python.org/3/builtins/functions.html#bool)*

Return True if this source requires authentication/API keys.

#### *abstractmethod* search(criteria)

Search for jobs using the given criteria.

* **Parameters:**
  **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – SearchCriteria object with search parameters
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects
* **Raises:**
  * [**SourceConfigError**](_autosummary/hired.search.base.html.md#hired.search.base.SourceConfigError) – If the source is not properly configured
  * [**Exception**](https://docs.python.org/3/builtins/exceptions.html#Exception) – For other errors during search

#### validate_configured()

Validate that the source is configured, raise error if not.

* **Raises:**
  [**SourceConfigError**](_autosummary/hired.search.base.html.md#hired.search.base.SourceConfigError) – If the source is not properly configured
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.search.base.JobType(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Standardized job types across all sources.

### *class* hired.search.base.LocationInfo(city=None, state=None, country=None, postal_code=None, raw=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Location information for a job.

### *class* hired.search.base.SearchCriteria(query, location=None, country=None, city=None, state=None, postal_code=None, distance_miles=None, job_type=None, is_remote=None, posted_within_days=None, results_wanted=20, offset=0, min_salary=None, max_salary=None, keywords=<factory>, exclude_keywords=<factory>, source_params=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Standardized search criteria across all sources.

Different sources may not support all criteria, but this provides
a consistent interface for users.

### *exception* hired.search.base.SourceConfigError

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

Raised when a source is not properly configured.


# _autosummary/hired.search.facade.html.md

# hired.search.facade

Main facade for job search functionality.

### Classes

| [`JobSources`](_autosummary/hired.search.facade.html.md#hired.search.facade.JobSources)([registry])   | Main facade for accessing job search sources.   |
|---------------------------------------------------------------------------|-------------------------------------------------|

### *class* hired.search.facade.JobSources(registry=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Main facade for accessing job search sources.

Provides both mapping interface (dict-like access) and attribute access
to registered job sources.

### Examples

```pycon
>>> sources = JobSources()
>>> # List all available sources
>>> sources.list()
['jobspy', 'usajobs', 'adzuna']
```

```pycon
>>> # Access via attribute
>>> results = sources.jobspy.search(SearchCriteria(query="python developer"))
```

```pycon
>>> # Access via mapping
>>> results = sources['indeed'].search(SearchCriteria(query="data scientist"))
```

```pycon
>>> # Search across multiple sources
>>> results = sources.search_all(
...     SearchCriteria(query="software engineer", location="San Francisco")
... )
```

#### get_info(name)

Get information about a source.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dictionary with source information including setup instructions

#### get_source(name)

Get a source by name.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)
* **Returns:**
  JobSearchSource instance
* **Raises:**
  [**KeyError**](https://docs.python.org/3/builtins/exceptions.html#KeyError) – If source not found

#### keys()

Get list of source names (dict-like interface).

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### list()

List all registered sources.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of source names

#### list_available()

List sources that are configured and ready to use.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of configured source names

#### list_unconfigured()

List sources that need configuration.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of unconfigured source names

#### print_status()

Print the status of all registered sources.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### search(source_name, criteria)

Search using a specific source.

* **Parameters:**
  * **source_name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source to use
  * **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects

#### search_all(criteria, sources=None, skip_unconfigured=True)

Search across multiple sources.

* **Parameters:**
  * **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
  * **sources** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]) – Optional list of source names. If None, uses all available sources.
  * **skip_unconfigured** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – If True, skip sources that are not configured
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  Combined list of JobResult objects from all sources


# _autosummary/hired.search.html.md

# hired.search

Job search functionality for the hired package.

This module provides a unified interface for searching jobs across
multiple sources (Indeed, LinkedIn, USAJobs, Adzuna, etc.).

Example usage:

```pycon
>>> from hired.search import JobSources, SearchCriteria
>>>
>>> # Create job sources facade
>>> sources = JobSources()
>>>
>>> # List available sources
>>> print(sources.list_available())
>>>
>>> # Search using a specific source
>>> criteria = SearchCriteria(
...     query="python developer",
...     location="San Francisco, CA",
...     results_wanted=20
... )
>>> results = sources.jobspy.search(criteria)
>>>
>>> # Or search across all sources
>>> all_results = sources.search_all(criteria)
```

### Functions

| [`get_registry`](_autosummary/hired.search.html.md#hired.search.get_registry)()                          | Get the global source registry.             |
|------------------------------------------------------------------------------------------|---------------------------------------------|
| [`register_source`](_autosummary/hired.search.html.md#hired.search.register_source)(source[, source_class]) | Register a source with the global registry. |

### Classes

| [`JobSources`](_autosummary/hired.search.html.md#hired.search.JobSources)([registry])                          | Main facade for accessing job search sources.    |
|--------------------------------------------------------------------------------------------------|--------------------------------------------------|
| [`SearchCriteria`](_autosummary/hired.search.html.md#hired.search.SearchCriteria)(query[, location, country, ...]) | Standardized search criteria across all sources. |
| [`JobResult`](_autosummary/hired.search.html.md#hired.search.JobResult)(title, source[, company, ...])        | Standardized job result across all sources.      |
| [`JobSearchSource`](_autosummary/hired.search.html.md#hired.search.JobSearchSource)()                               | Abstract base class for job search sources.      |
| [`JobType`](_autosummary/hired.search.html.md#hired.search.JobType)(\*values)                               | Standardized job types across all sources.       |
| [`LocationInfo`](_autosummary/hired.search.html.md#hired.search.LocationInfo)([city, state, country, ...])       | Location information for a job.                  |
| [`CompensationInfo`](_autosummary/hired.search.html.md#hired.search.CompensationInfo)([min_amount, max_amount, ...]) | Compensation information for a job.              |
| [`SourceRegistry`](_autosummary/hired.search.html.md#hired.search.SourceRegistry)()                                | Registry for job search sources.                 |
| [`JobSpySource`](_autosummary/hired.search.html.md#hired.search.JobSpySource)([sites, proxies])                  | JobSpy source implementation.                    |
| [`USAJobsSource`](_autosummary/hired.search.html.md#hired.search.USAJobsSource)([api_key, email])                 | USAJobs API source implementation.               |
| [`AdzunaSource`](_autosummary/hired.search.html.md#hired.search.AdzunaSource)([app_id, app_key, country])        | Adzuna API source implementation.                |

### Exceptions

| [`SourceConfigError`](_autosummary/hired.search.html.md#hired.search.SourceConfigError)   | Raised when a source is not properly configured.   |
|----------------------------------------------------------------------|----------------------------------------------------|

### *class* hired.search.AdzunaSource(app_id=None, app_key=None, country='us')

Bases: [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)

Adzuna API source implementation.

Searches international job postings via the Adzuna Jobs API.
Requires a free API key from [https://developer.adzuna.com/](https://developer.adzuna.com/).

#### *property* display_name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the display name of this source (e.g., ‘Indeed’, ‘USAJobs’).

#### get_setup_instructions()

Return setup instructions for this source.

Should include:

- Where to get API keys if needed
- Environment variables or config file settings
- URLs for documentation

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Multi-line string with setup instructions.

#### is_configured()

Check if this source is properly configured.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if the source is ready to use, False otherwise.

#### *property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the name of this source (e.g., ‘indeed’, ‘usajobs’).

#### *property* requires_auth *: [bool](https://docs.python.org/3/builtins/functions.html#bool)*

Return True if this source requires authentication/API keys.

#### search(criteria)

Search for jobs using Adzuna API.

* **Parameters:**
  **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects

### *class* hired.search.CompensationInfo(min_amount=None, max_amount=None, currency=None, interval=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Compensation information for a job.

### *class* hired.search.JobResult(title, source, company=None, company_url=None, job_url=None, location=None, is_remote=None, description=None, job_type=None, compensation=None, date_posted=None, date_updated=None, application_deadline=None, skills=<factory>, benefits=<factory>, emails=<factory>, raw_data=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Standardized job result across all sources.

This provides a unified interface regardless of which source
the job was retrieved from.

#### to_dict()

Convert JobResult to dictionary.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.search.JobSearchSource

Bases: [`ABC`](https://docs.python.org/3/library/abc.html#abc.ABC)

Abstract base class for job search sources.

All job search sources must implement this interface to be
registered in the system.

#### *abstract property* display_name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the display name of this source (e.g., ‘Indeed’, ‘USAJobs’).

#### *abstractmethod* get_setup_instructions()

Return setup instructions for this source.

Should include:

- Where to get API keys if needed
- Environment variables or config file settings
- URLs for documentation

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Multi-line string with setup instructions.

#### *abstractmethod* is_configured()

Check if this source is properly configured.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if the source is ready to use, False otherwise.

#### *abstract property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the name of this source (e.g., ‘indeed’, ‘usajobs’).

#### *abstract property* requires_auth *: [bool](https://docs.python.org/3/builtins/functions.html#bool)*

Return True if this source requires authentication/API keys.

#### *abstractmethod* search(criteria)

Search for jobs using the given criteria.

* **Parameters:**
  **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – SearchCriteria object with search parameters
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects
* **Raises:**
  * [**SourceConfigError**](_autosummary/hired.search.html.md#hired.search.SourceConfigError) – If the source is not properly configured
  * [**Exception**](https://docs.python.org/3/builtins/exceptions.html#Exception) – For other errors during search

#### validate_configured()

Validate that the source is configured, raise error if not.

* **Raises:**
  [**SourceConfigError**](_autosummary/hired.search.html.md#hired.search.SourceConfigError) – If the source is not properly configured
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.search.JobSources(registry=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Main facade for accessing job search sources.

Provides both mapping interface (dict-like access) and attribute access
to registered job sources.

### Examples

```pycon
>>> sources = JobSources()
>>> # List all available sources
>>> sources.list()
['jobspy', 'usajobs', 'adzuna']
```

```pycon
>>> # Access via attribute
>>> results = sources.jobspy.search(SearchCriteria(query="python developer"))
```

```pycon
>>> # Access via mapping
>>> results = sources['indeed'].search(SearchCriteria(query="data scientist"))
```

```pycon
>>> # Search across multiple sources
>>> results = sources.search_all(
...     SearchCriteria(query="software engineer", location="San Francisco")
... )
```

#### get_info(name)

Get information about a source.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dictionary with source information including setup instructions

#### get_source(name)

Get a source by name.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)
* **Returns:**
  JobSearchSource instance
* **Raises:**
  [**KeyError**](https://docs.python.org/3/builtins/exceptions.html#KeyError) – If source not found

#### keys()

Get list of source names (dict-like interface).

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### list()

List all registered sources.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of source names

#### list_available()

List sources that are configured and ready to use.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of configured source names

#### list_unconfigured()

List sources that need configuration.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of unconfigured source names

#### print_status()

Print the status of all registered sources.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### search(source_name, criteria)

Search using a specific source.

* **Parameters:**
  * **source_name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source to use
  * **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects

#### search_all(criteria, sources=None, skip_unconfigured=True)

Search across multiple sources.

* **Parameters:**
  * **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
  * **sources** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]) – Optional list of source names. If None, uses all available sources.
  * **skip_unconfigured** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – If True, skip sources that are not configured
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  Combined list of JobResult objects from all sources

### *class* hired.search.JobSpySource(sites=None, proxies=None)

Bases: [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)

JobSpy source implementation.

Uses python-jobspy to scrape jobs from multiple sources simultaneously.
Does not require API keys, but may be subject to rate limiting.

#### *property* display_name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the display name of this source (e.g., ‘Indeed’, ‘USAJobs’).

#### get_setup_instructions()

Return setup instructions for this source.

Should include:

- Where to get API keys if needed
- Environment variables or config file settings
- URLs for documentation

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Multi-line string with setup instructions.

#### is_configured()

Check if this source is properly configured.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if the source is ready to use, False otherwise.

#### *property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the name of this source (e.g., ‘indeed’, ‘usajobs’).

#### *property* requires_auth *: [bool](https://docs.python.org/3/builtins/functions.html#bool)*

Return True if this source requires authentication/API keys.

#### search(criteria)

Search for jobs using JobSpy.

* **Parameters:**
  **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects

### *class* hired.search.JobType(\*values)

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Enum`](https://docs.python.org/3/library/enum.html#enum.Enum)

Standardized job types across all sources.

### *class* hired.search.LocationInfo(city=None, state=None, country=None, postal_code=None, raw=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Location information for a job.

### *class* hired.search.SearchCriteria(query, location=None, country=None, city=None, state=None, postal_code=None, distance_miles=None, job_type=None, is_remote=None, posted_within_days=None, results_wanted=20, offset=0, min_salary=None, max_salary=None, keywords=<factory>, exclude_keywords=<factory>, source_params=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Standardized search criteria across all sources.

Different sources may not support all criteria, but this provides
a consistent interface for users.

### *exception* hired.search.SourceConfigError

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

Raised when a source is not properly configured.

### *class* hired.search.SourceRegistry

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Registry for job search sources.

Provides a plugin system where sources can be registered
and retrieved by name.

#### get(name)

Get a source by name.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)
* **Returns:**
  JobSearchSource instance
* **Raises:**
  [**KeyError**](https://docs.python.org/3/builtins/exceptions.html#KeyError) – If source not found

#### get_source_info(name)

Get information about a source.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dictionary with source information

#### list_available_sources()

List sources that are properly configured and ready to use.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of source names that are configured

#### list_sources()

List all registered source names.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of source names

#### list_unconfigured_sources()

List sources that are registered but not configured.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of source names that need configuration

#### register(source, source_class=None)

Register a job search source.

* **Parameters:**
  * **source** ([`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)) – Instance of a JobSearchSource implementation
  * **source_class** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`Type`](https://docs.python.org/3/library/typing.html#typing.Type)[[`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)]]) – Optional class of the source for reference
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### unregister(name)

Unregister a source by name.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source to unregister
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### *class* hired.search.USAJobsSource(api_key=None, email=None)

Bases: [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)

USAJobs API source implementation.

Searches US Government job postings via the official USAJobs API.
Requires a free API key from [https://developer.usajobs.gov/](https://developer.usajobs.gov/).

#### *property* display_name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the display name of this source (e.g., ‘Indeed’, ‘USAJobs’).

#### get_setup_instructions()

Return setup instructions for this source.

Should include:

- Where to get API keys if needed
- Environment variables or config file settings
- URLs for documentation

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Multi-line string with setup instructions.

#### is_configured()

Check if this source is properly configured.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if the source is ready to use, False otherwise.

#### *property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the name of this source (e.g., ‘indeed’, ‘usajobs’).

#### *property* requires_auth *: [bool](https://docs.python.org/3/builtins/functions.html#bool)*

Return True if this source requires authentication/API keys.

#### search(criteria)

Search for jobs using USAJobs API.

* **Parameters:**
  **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects

### hired.search.get_registry()

Get the global source registry.

* **Return type:**
  [`SourceRegistry`](_autosummary/hired.search.registry.html.md#hired.search.registry.SourceRegistry)

### hired.search.register_source(source, source_class=None)

Register a source with the global registry.

* **Parameters:**
  * **source** ([`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)) – Instance of a JobSearchSource implementation
  * **source_class** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`Type`](https://docs.python.org/3/library/typing.html#typing.Type)[[`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)]]) – Optional class of the source for reference
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### Modules

| [`base`](_autosummary/hired.search.base.html.md#module-hired.search.base)         | Base classes and interfaces for job search functionality.   |
|----------------------------------------------------------------------------------------|-------------------------------------------------------------|
| [`facade`](_autosummary/hired.search.facade.html.md#module-hired.search.facade)     | Main facade for job search functionality.                   |
| [`registry`](_autosummary/hired.search.registry.html.md#module-hired.search.registry) | Registry system for managing job search sources.            |
| [`sources`](_autosummary/hired.search.sources.html.md#module-hired.search.sources)   | Job search source implementations.                          |


# _autosummary/hired.search.registry.html.md

# hired.search.registry

Registry system for managing job search sources.

### Functions

| [`get_registry`](_autosummary/hired.search.registry.html.md#hired.search.registry.get_registry)()                          | Get the global source registry.             |
|------------------------------------------------------------------------------------------|---------------------------------------------|
| [`register_source`](_autosummary/hired.search.registry.html.md#hired.search.registry.register_source)(source[, source_class]) | Register a source with the global registry. |

### Classes

| [`SourceRegistry`](_autosummary/hired.search.registry.html.md#hired.search.registry.SourceRegistry)()   | Registry for job search sources.   |
|---------------------------------------------------------------------|------------------------------------|

### *class* hired.search.registry.SourceRegistry

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Registry for job search sources.

Provides a plugin system where sources can be registered
and retrieved by name.

#### get(name)

Get a source by name.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)
* **Returns:**
  JobSearchSource instance
* **Raises:**
  [**KeyError**](https://docs.python.org/3/builtins/exceptions.html#KeyError) – If source not found

#### get_source_info(name)

Get information about a source.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source
* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dictionary with source information

#### list_available_sources()

List sources that are properly configured and ready to use.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of source names that are configured

#### list_sources()

List all registered source names.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of source names

#### list_unconfigured_sources()

List sources that are registered but not configured.

* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]
* **Returns:**
  List of source names that need configuration

#### register(source, source_class=None)

Register a job search source.

* **Parameters:**
  * **source** ([`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)) – Instance of a JobSearchSource implementation
  * **source_class** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`Type`](https://docs.python.org/3/library/typing.html#typing.Type)[[`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)]]) – Optional class of the source for reference
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### unregister(name)

Unregister a source by name.

* **Parameters:**
  **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the source to unregister
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### hired.search.registry.get_registry()

Get the global source registry.

* **Return type:**
  [`SourceRegistry`](_autosummary/hired.search.registry.html.md#hired.search.registry.SourceRegistry)

### hired.search.registry.register_source(source, source_class=None)

Register a source with the global registry.

* **Parameters:**
  * **source** ([`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)) – Instance of a JobSearchSource implementation
  * **source_class** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`Type`](https://docs.python.org/3/library/typing.html#typing.Type)[[`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)]]) – Optional class of the source for reference
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)


# _autosummary/hired.search.sources.adzuna.html.md

# hired.search.sources.adzuna

Adzuna source adapter.

Accesses the Adzuna Jobs API ([https://developer.adzuna.com/](https://developer.adzuna.com/)).
Requires a free API key (app_id and app_key) from the Adzuna Developer Portal.

### Functions

| [`get_adzuna_source`](_autosummary/hired.search.sources.adzuna.html.md#hired.search.sources.adzuna.get_adzuna_source)()   | Get the default Adzuna source instance.   |
|------------------------------------------------------------------------|-------------------------------------------|

### Classes

| [`AdzunaSource`](_autosummary/hired.search.sources.adzuna.html.md#hired.search.sources.adzuna.AdzunaSource)([app_id, app_key, country])   | Adzuna API source implementation.   |
|---------------------------------------------------------------------------------------------|-------------------------------------|

### *class* hired.search.sources.adzuna.AdzunaSource(app_id=None, app_key=None, country='us')

Bases: [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)

Adzuna API source implementation.

Searches international job postings via the Adzuna Jobs API.
Requires a free API key from [https://developer.adzuna.com/](https://developer.adzuna.com/).

#### *property* display_name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the display name of this source (e.g., ‘Indeed’, ‘USAJobs’).

#### get_setup_instructions()

Return setup instructions for this source.

Should include:

- Where to get API keys if needed
- Environment variables or config file settings
- URLs for documentation

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Multi-line string with setup instructions.

#### is_configured()

Check if this source is properly configured.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if the source is ready to use, False otherwise.

#### *property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the name of this source (e.g., ‘indeed’, ‘usajobs’).

#### *property* requires_auth *: [bool](https://docs.python.org/3/builtins/functions.html#bool)*

Return True if this source requires authentication/API keys.

#### search(criteria)

Search for jobs using Adzuna API.

* **Parameters:**
  **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects

### hired.search.sources.adzuna.get_adzuna_source()

Get the default Adzuna source instance.

* **Return type:**
  [`AdzunaSource`](_autosummary/hired.search.sources.adzuna.html.md#hired.search.sources.adzuna.AdzunaSource)


# _autosummary/hired.search.sources.html.md

# hired.search.sources

Job search source implementations.

Each module in this package provides a specific job search source adapter.

### Modules

| [`adzuna`](_autosummary/hired.search.sources.adzuna.html.md#module-hired.search.sources.adzuna)   | Adzuna source adapter.   |
|----------------------------------------------------------------------------------------------|--------------------------|
| [`jobspy`](_autosummary/hired.search.sources.jobspy.html.md#module-hired.search.sources.jobspy)   | JobSpy source adapter.   |
| [`usajobs`](_autosummary/hired.search.sources.usajobs.html.md#module-hired.search.sources.usajobs) | USAJobs source adapter.  |


# _autosummary/hired.search.sources.jobspy.html.md

# hired.search.sources.jobspy

JobSpy source adapter.

Wraps the python-jobspy package to search across multiple job boards
(LinkedIn, Indeed, Glassdoor, ZipRecruiter, Google) concurrently.

### Functions

| [`get_jobspy_source`](_autosummary/hired.search.sources.jobspy.html.md#hired.search.sources.jobspy.get_jobspy_source)()   | Get the default JobSpy source instance.   |
|------------------------------------------------------------------------|-------------------------------------------|

### Classes

| [`JobSpySource`](_autosummary/hired.search.sources.jobspy.html.md#hired.search.sources.jobspy.JobSpySource)([sites, proxies])   | JobSpy source implementation.   |
|-----------------------------------------------------------------------------------|---------------------------------|

### *class* hired.search.sources.jobspy.JobSpySource(sites=None, proxies=None)

Bases: [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)

JobSpy source implementation.

Uses python-jobspy to scrape jobs from multiple sources simultaneously.
Does not require API keys, but may be subject to rate limiting.

#### *property* display_name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the display name of this source (e.g., ‘Indeed’, ‘USAJobs’).

#### get_setup_instructions()

Return setup instructions for this source.

Should include:

- Where to get API keys if needed
- Environment variables or config file settings
- URLs for documentation

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Multi-line string with setup instructions.

#### is_configured()

Check if this source is properly configured.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if the source is ready to use, False otherwise.

#### *property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the name of this source (e.g., ‘indeed’, ‘usajobs’).

#### *property* requires_auth *: [bool](https://docs.python.org/3/builtins/functions.html#bool)*

Return True if this source requires authentication/API keys.

#### search(criteria)

Search for jobs using JobSpy.

* **Parameters:**
  **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects

### hired.search.sources.jobspy.get_jobspy_source()

Get the default JobSpy source instance.

* **Return type:**
  [`JobSpySource`](_autosummary/hired.search.sources.jobspy.html.md#hired.search.sources.jobspy.JobSpySource)


# _autosummary/hired.search.sources.usajobs.html.md

# hired.search.sources.usajobs

USAJobs source adapter.

Accesses the official US Government jobs API ([https://developer.usajobs.gov/](https://developer.usajobs.gov/)).
Requires a free API key obtained from the USAJobs Developer Portal.

### Functions

| [`get_usajobs_source`](_autosummary/hired.search.sources.usajobs.html.md#hired.search.sources.usajobs.get_usajobs_source)()   | Get the default USAJobs source instance.   |
|-------------------------------------------------------------------------|--------------------------------------------|

### Classes

| [`USAJobsSource`](_autosummary/hired.search.sources.usajobs.html.md#hired.search.sources.usajobs.USAJobsSource)([api_key, email])   | USAJobs API source implementation.   |
|------------------------------------------------------------------------------------|--------------------------------------|

### *class* hired.search.sources.usajobs.USAJobsSource(api_key=None, email=None)

Bases: [`JobSearchSource`](_autosummary/hired.search.base.html.md#hired.search.base.JobSearchSource)

USAJobs API source implementation.

Searches US Government job postings via the official USAJobs API.
Requires a free API key from [https://developer.usajobs.gov/](https://developer.usajobs.gov/).

#### *property* display_name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the display name of this source (e.g., ‘Indeed’, ‘USAJobs’).

#### get_setup_instructions()

Return setup instructions for this source.

Should include:

- Where to get API keys if needed
- Environment variables or config file settings
- URLs for documentation

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  Multi-line string with setup instructions.

#### is_configured()

Check if this source is properly configured.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if the source is ready to use, False otherwise.

#### *property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

Return the name of this source (e.g., ‘indeed’, ‘usajobs’).

#### *property* requires_auth *: [bool](https://docs.python.org/3/builtins/functions.html#bool)*

Return True if this source requires authentication/API keys.

#### search(criteria)

Search for jobs using USAJobs API.

* **Parameters:**
  **criteria** ([`SearchCriteria`](_autosummary/hired.search.base.html.md#hired.search.base.SearchCriteria)) – Search criteria
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]
* **Returns:**
  List of JobResult objects

### hired.search.sources.usajobs.get_usajobs_source()

Get the default USAJobs source instance.

* **Return type:**
  [`USAJobsSource`](_autosummary/hired.search.sources.usajobs.html.md#hired.search.sources.usajobs.USAJobsSource)


# _autosummary/hired.tools.html.md

# hired.tools

High-level orchestration functions - the main API.

These are the primary user-facing functions that coordinate
the entire pipeline.

### Functions

| [`mk_content_for_resume`](_autosummary/hired.tools.html.md#hired.tools.mk_content_for_resume)(candidate_info_src, ...)    | Generate resume content from candidate and job information.                                                |
|----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------|
| [`mk_resume`](_autosummary/hired.tools.html.md#hired.tools.mk_resume)(content[, rendering, output_path, ...]) | Render resume content to final format.                                                                     |
| [`render_resume_with_template_and_css`](_autosummary/hired.tools.html.md#hired.tools.render_resume_with_template_and_css)(content, ...) | Render a resume dict (or pydantic model) to PDF using a specific HTML template file and optional CSS file. |

### hired.tools.mk_content_for_resume(candidate_info_src, job_info_src, , agent=None, validate=True, strict=False)

Generate resume content from candidate and job information.

* **Parameters:**
  * **candidate_info_src** (`Union`[[`ContentSource`](_autosummary/hired.base.html.md#hired.base.ContentSource), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]) – Candidate information as ContentSource, file path, or dict
  * **job_info_src** (`Union`[[`ContentSource`](_autosummary/hired.base.html.md#hired.base.ContentSource), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)], [`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Job information as ContentSource, file path, dict, or JobResult
  * **agent** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – Optional AI agent for content generation
  * **validate** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – Whether to validate the generated content
  * **strict** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – Whether to use strict validation
* **Return type:**
  [`ResumeSchemaExtended`](_autosummary/hired.base.html.md#hired.base.ResumeSchemaExtended)
* **Returns:**
  ResumeSchemaExtended object with generated content

### Examples

```pycon
>>> # Using file paths
>>> content = mk_content_for_resume("candidate.json", "job.txt")
>>>
>>> # Using JobResult from job search
>>> from hired import JobSources, SearchCriteria
>>> sources = JobSources()
>>> jobs = sources.jobspy.search(SearchCriteria(query="python developer"))
>>> content = mk_content_for_resume(candidate_dict, jobs[0])
```

### hired.tools.mk_resume(content, rendering=None, , output_path=None, strict=False)

Render resume content to final format.

* **Return type:**
  [`bytes`](https://docs.python.org/3/builtins/stdtypes.html#bytes)

### hired.tools.render_resume_with_template_and_css(content, template_path, css_path=None, , format='pdf', strict=False)

Render a resume dict (or pydantic model) to PDF using a specific
HTML template file and optional CSS file.

* **Parameters:**
  * **content** (`Union`[[`ResumeSchemaExtended`](_autosummary/hired.base.html.md#hired.base.ResumeSchemaExtended), [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]]) – Resume content as a dict or ResumeSchemaExtended instance.
  * **template_path** (`Union`[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)]) – Path to an HTML/Jinja template file to render from.
  * **css_path** (`Union`[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path), [`None`](https://docs.python.org/3/builtins/constants.html#None)]) – Optional path to a CSS file; its contents will be passed to
    the renderer as `custom_css` so PDF rendering picks up the styles.
  * **format** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Output format, ‘pdf’ or ‘html’. Default is ‘pdf’.
  * **strict** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – If True, enable stricter schema validation.
* **Return type:**
  [`bytes`](https://docs.python.org/3/builtins/stdtypes.html#bytes)
* **Returns:**
  PDF file bytes.


# _autosummary/hired.tracking.html.md

# hired.tracking

Application tracking system for managing job applications.

Track applications, statuses, follow-ups, and outcomes.

### Classes

| [`Application`](_autosummary/hired.tracking.html.md#hired.tracking.Application)(job_title, company[, id, ...])   | Represents a job application.                |
|-----------------------------------------------------------------------------------------------|----------------------------------------------|
| [`ApplicationTracker`](_autosummary/hired.tracking.html.md#hired.tracking.ApplicationTracker)([db_path])                | Track job applications in a SQLite database. |

### *class* hired.tracking.Application(job_title, company, id=None, job_url=None, location=None, salary_range=None, resume_path=None, cover_letter_path=None, status='draft', applied_date=None, created_at=None, updated_at=None, follow_up_date=None, last_contact_date=None, notes='', contacts='', interview_dates='', match_score=None, source=None, source_data='')

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Represents a job application.

#### *classmethod* from_job_result(job, \*\*kwargs)

Create an Application from a JobResult.

* **Parameters:**
  * **job** ([`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)) – JobResult object
  * **\*\*kwargs** ([`Any`](https://docs.python.org/3/library/typing.html#typing.Any)) – Additional fields to set
* **Return type:**
  [`Application`](_autosummary/hired.tracking.html.md#hired.tracking.Application)
* **Returns:**
  Application object

#### to_dict()

Convert to dictionary.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### *class* hired.tracking.ApplicationTracker(db_path=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Track job applications in a SQLite database.

### Examples

```pycon
>>> tracker = ApplicationTracker()
>>>
>>> # Add application from job search
>>> app_id = tracker.add_application(
...     job=job_result,
...     resume_path="resume.pdf",
...     status="applied"
... )
>>>
>>> # Update status
>>> tracker.update_status(app_id, "interview")
>>>
>>> # Get all applications in interview stage
>>> interviews = tracker.get_applications(status="interview")
>>>
>>> # Get statistics
>>> stats = tracker.get_statistics()
```

#### add_application(job=None, \*\*kwargs)

Add a new application.

* **Parameters:**
  * **job** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`JobResult`](_autosummary/hired.search.base.html.md#hired.search.base.JobResult)]) – Optional JobResult to create application from
  * **\*\*kwargs** ([`Any`](https://docs.python.org/3/library/typing.html#typing.Any)) – Additional fields (or all fields if job not provided)
* **Return type:**
  [`int`](https://docs.python.org/3/builtins/functions.html#int)
* **Returns:**
  ID of created application

### Examples

```pycon
>>> # From JobResult
>>> app_id = tracker.add_application(
...     job=job_result,
...     resume_path="resume.pdf",
...     status="applied"
... )
>>>
>>> # Manual entry
>>> app_id = tracker.add_application(
...     job_title="Software Engineer",
...     company="TechCorp",
...     status="applied"
... )
```

#### delete_application(app_id)

Delete an application.

* **Parameters:**
  **app_id** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Application ID
* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if deleted, False if not found

#### export_to_csv(output_path)

Export applications to CSV file.

* **Parameters:**
  **output_path** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Path to output CSV file
* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### get_application(app_id)

Get application by ID.

* **Parameters:**
  **app_id** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Application ID
* **Return type:**
  [`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`Application`](_autosummary/hired.tracking.html.md#hired.tracking.Application)]
* **Returns:**
  Application object or None if not found

#### get_applications(status=None, company=None, limit=None)

Get applications with optional filtering.

* **Parameters:**
  * **status** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Filter by status
  * **company** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Filter by company name
  * **limit** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`int`](https://docs.python.org/3/builtins/functions.html#int)]) – Maximum number of results
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`Application`](_autosummary/hired.tracking.html.md#hired.tracking.Application)]
* **Returns:**
  List of Application objects

#### get_follow_ups_due(days=7)

Get applications that need follow-up.

* **Parameters:**
  **days** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Number of days to look ahead
* **Return type:**
  [`List`](https://docs.python.org/3/library/typing.html#typing.List)[[`Application`](_autosummary/hired.tracking.html.md#hired.tracking.Application)]
* **Returns:**
  List of Application objects needing follow-up

#### get_statistics()

Get application statistics.

* **Return type:**
  [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]
* **Returns:**
  Dictionary with statistics

#### update_application(app_id, \*\*kwargs)

Update application fields.

* **Parameters:**
  * **app_id** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Application ID
  * **\*\*kwargs** ([`Any`](https://docs.python.org/3/library/typing.html#typing.Any)) – Fields to update
* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if updated, False if not found

#### update_status(app_id, status, notes=None)

Update application status.

* **Parameters:**
  * **app_id** ([`int`](https://docs.python.org/3/builtins/functions.html#int)) – Application ID
  * **status** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – New status
  * **notes** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Optional notes to append
* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)
* **Returns:**
  True if updated, False if not found


# _autosummary/hired.util.html.md

# hired.util

Utilities for external dependencies and general helpers.
All imports here are external to the hired package.

### Functions

| [`dump_yaml`](_autosummary/hired.util.html.md#hired.util.dump_yaml)(d, yaml_path)                           | Dumps a dictionary to a YAML file using PyYAML, preserving key order and using a readable block style.   |
|----------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
| [`ensure_resume_content_dict`](_autosummary/hired.util.html.md#hired.util.ensure_resume_content_dict)(content_src)           | Get a schema-valid resume dict from various sources (json file, json string, dict, ...)                  |
| [`extract_friendly_errors`](_autosummary/hired.util.html.md#hired.util.extract_friendly_errors)(error_obj[, schema, ...]) | Extracts a generator of user-friendly error messages from a validation error object.                     |
| [`get_jsonschema_errors`](_autosummary/hired.util.html.md#hired.util.get_jsonschema_errors)(content[, schema_path])     | Return a list of jsonschema validation error messages for the content.                                   |
| [`load_yaml`](_autosummary/hired.util.html.md#hired.util.load_yaml)(yaml_path)                              | Loads a YAML file using PyYAML.                                                                          |
| [`normalize_and_validate_resume`](_autosummary/hired.util.html.md#hired.util.normalize_and_validate_resume)(raw, \*[, strict])  | Normalize and validate a resume-like mapping.                                                            |
| `refresh_resume_schema`()                                                                          |                                                                                                          |
| [`validate_resume_content_dict`](_autosummary/hired.util.html.md#hired.util.validate_resume_content_dict)(content, \*[, ...])  | Validate resume content using ResumeSchemaExtended (which allows extra fields).                          |
| `validation_friendly_errors_string`(error_obj)                                                     |                                                                                                          |

### hired.util.dump_yaml(d, yaml_path)

Dumps a dictionary to a YAML file using PyYAML,
preserving key order and using a readable block style.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### hired.util.ensure_resume_content_dict(content_src)

Get a schema-valid resume dict from various sources
(json file, json string, dict, …)

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### hired.util.extract_friendly_errors(error_obj, schema=None, data=None)

Extracts a generator of user-friendly error messages from a validation error object.

This function works with both Pydantic’s ValidationError and jsonschema’s
ValidationError to provide a consistent output.

* **Parameters:**
  **error_obj** (`Union`[`ValidationError`, `ValidationError`]) – The ValidationError instance to process.
* **Yields:**
  A tuple of (field, message) for each validation error.
* **Return type:**
  [*Iterator*](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator)[[*tuple*](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[*Any*](https://docs.python.org/3/library/typing.html#typing.Any), [*str*](https://docs.python.org/3/builtins/stdtypes.html#str)]]

### hired.util.get_jsonschema_errors(content, schema_path=None)

Return a list of jsonschema validation error messages for the content.

If jsonschema is not available or the schema file is missing, returns an
empty list.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### hired.util.load_yaml(yaml_path)

Loads a YAML file using PyYAML.
This works in Python 3.7+ because dicts preserve insertion order.

* **Return type:**
  [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)

### hired.util.normalize_and_validate_resume(raw, , strict=True)

Normalize and validate a resume-like mapping.

- Prunes None values.
- Validates via Pydantic ResumeSchemaExtended (allows extra fields).
- If strict is True and jsonschema is available, will attempt schema
  validation against the packaged JSON schema (best-effort).

Returns a ResumeSchemaExtended instance on success. Raises
pydantic.ValidationError on failure.

* **Return type:**
  [`ResumeSchemaExtended`](_autosummary/hired.base.html.md#hired.base.ResumeSchemaExtended)

### hired.util.validate_resume_content_dict(content, , raise_errors=True)

Validate resume content using ResumeSchemaExtended (which allows extra fields).

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]


# about-this-build.html.md

<!-- generated by epythet -->

# About this build

This documentation was built on **2026-10-14 02:29 UTC** from commit <a href="https://github.com/thorwhalen/hired/commit/2b5ebd05dcebba754734c6d61e268952b1f1ad2f"><code>2b5ebd0</code></a> on branch <code>main</code>, for **hired 0.0.23** (from <code>pyproject.toml</code>).

#### NOTE
Nothing suggests a mismatch: the tree was clean at the commit above, and the documented version is the one on PyPI.

## Source

|                     |                                                                                                                                                         |
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
| Commit              | <a href="https://github.com/thorwhalen/hired/commit/2b5ebd05dcebba754734c6d61e268952b1f1ad2f"><code>2b5ebd05dcebba754734c6d61e268952b1f1ad2f</code></a> |
| Branch              | <code>main</code>                                                                                                                                       |
| Tags at this commit | none                                                                                                                                                    |
| Working tree        | clean                                                                                                                                                   |
| Remote              | <code>https://github.com/thorwhalen/hired</code>                                                                                                        |

## Continuous integration

|              |                                                                                            |
|--------------|--------------------------------------------------------------------------------------------|
| Repository   | <code>thorwhalen/hired</code>                                                              |
| Run          | <a href="https://github.com/thorwhalen/hired/actions/runs/38501127291">38501127291</a>     |
| Ref          | <code>refs/heads/main</code>                                                               |
| Event commit | <code>2b5ebd05dcebba754734c6d61e268952b1f1ad2f</code> (in the history of the built commit) |

## Tools

|          |         |
|----------|---------|
| epythet  | 0.2.17  |
| Sphinx   | 9.1.0   |
| docutils | 0.22.4  |
| Python   | 3.12.15 |

## Configuration as resolved

|               |                                                                   |
|---------------|-------------------------------------------------------------------|
| theme         | <code>auto</code> (Sphinx theme <code>pydata_sphinx_theme</code>) |
| accent        | <code>#735300</code>                                              |
| api_generator | <code>autosummary</code>                                          |
| ignore        | <code>tests/</code>, <code>scrap/</code>, <code>examples/</code>  |
| agent_outputs | <code>true</code>                                                 |
| aggregates    | <code>md</code>                                                   |
| ai_artifacts  | <code>true</code>                                                 |

## Package on PyPI

Latest release: <a href="https://pypi.org/project/hired/0.0.23/">0.0.23</a>, the same as the documented version.

## Reproduce

```bash
git clone https://github.com/thorwhalen/hired && cd hired
git checkout 2b5ebd05dcebba754734c6d61e268952b1f1ad2f
pip install "epythet==0.2.17"
epythet quickstart . --ignore tests/ scrap/ examples/
```

The same data, for machines: <a href="build_info.json"><code>build_info.json</code></a> (schema version 1).


# ai-agents.html.md

<!-- generated by epythet -->

# For AI agents

`hired` ships artifacts for coding agents alongside its code. This page lists
them, says where each lives in the repository, and points at the
machine-readable copies of this documentation.

## Skills

Skills are folders holding a `SKILL.md` (the [Agent Skills](https://agentskills.io) format): a description that tells an agent when to use it and a body with the procedure. Install one into your agent with `gh skill` (any host: `--agent claude-code`, `copilot`, `cursor`, `codex`, `gemini`), or use the copy bundled in the wheel.

### `hired-align`

Use to analyze how well a candidate fits a job description and to accumulate reusable knowledge about the candidate. Triggers on “analyze this JD against my profile”, “how well do I match this job”, “what are my gaps for this role”, “help me respond to a recruiter about this job”, “align my profile to this job description”, or when given one or more JDs to assess for a candidate. Classifies each requirement into strong-match / adjacent-transferable / gap-learnable / gap-hard, asks clarifying questions instead of assuming gaps, and persists everything (facts + Q&A + reports) outside the repo under ~/.local/share/hired/.

```bash
gh skill install thorwhalen/hired hired-align --agent claude-code
```

Source: [`skills/hired-align`](https://github.com/thorwhalen/hired/tree/HEAD/skills/hired-align).

### `hired-dev`

Use when developing or modifying the `hired` package itself — adding a renderer or job-search source, working on the resume pipeline / AI agents (`tools.py`, `content.py`, `resume_agent.py`), the workflow helpers, or hired’s dependencies/CI. Triggers on editing files under the hired repo, “add a job source to hired”, “add a renderer”, “wire the AI agent”, or changing hired’s extras.

```bash
gh skill install thorwhalen/hired hired-dev --agent claude-code
```

Source: [`skills/hired-dev`](https://github.com/thorwhalen/hired/tree/HEAD/skills/hired-dev).

### `hired-interview-prep`

Use to prepare a candidate for a headhunter call or company interview. Triggers on “prep me for the interview”, “I have a call with the recruiter/headhunter”, “help me get ready for the Socure interview”, “what should I study before the interview”, “research the company before I talk to them”. Refreshes the alignment report from the latest Q&A, researches the company and people, and produces study briefings on the subjects/terminology the candidate is weakest on — each anchored by analogy to the candidate’s own experience.

```bash
gh skill install thorwhalen/hired hired-interview-prep --agent claude-code
```

Source: [`skills/hired-interview-prep`](https://github.com/thorwhalen/hired/tree/HEAD/skills/hired-interview-prep).

### `hired-usage`

Use when helping a job seeker with `hired` — tailor/generate a resume and render it to PDF/HTML, search jobs across boards, score/match a resume to a job, run an ATS-compatibility check, draft a cover letter, or track applications. Triggers on “tailor/build a resume”, “render resume to PDF”, “search for jobs”, “match resume to job”, “ATS check”, “cover letter”, “track applications”. Core install `pip install hired`; features need extras (`hired[pdf]`, `hired[search]`, `hired[ai]`, `hired[all]`).

```bash
gh skill install thorwhalen/hired hired-usage --agent claude-code
```

Source: [`skills/hired-usage`](https://github.com/thorwhalen/hired/tree/HEAD/skills/hired-usage).

## Subagents

Subagents are Markdown files with a frontmatter (`name`, `description`, `tools`) and a system prompt as the body. Copy one into your project’s `.claude/agents/` (or your agent host’s equivalent) to delegate the task it describes.

### `hired-alignment-report`

Generates a complete JD↔candidate alignment report from ALL available evidence (candidate facts, Q&A, company report) — deliberately WITHOUT reading any existing alignment report, so it is an unanchored, reusable generator. Use to create a report for a new JD, or as the “fresh second opinion” in a heavy alignment review.

Source: [`.claude/agents/hired-alignment-report.md`](https://github.com/thorwhalen/hired/tree/HEAD/.claude/agents/hired-alignment-report.md); tools: `Read, Bash, Grep`.

### `hired-alignment-review`

Reviews and refreshes an existing JD↔candidate alignment report against current evidence, in light (default) or heavy mode. Light mode patches false negatives the newer Q&A now resolves; heavy mode regenerates a fresh report from all evidence and adversarially diffs it against the existing one. Always proposes changes for approval — never applies silently.

Source: [`.claude/agents/hired-alignment-review.md`](https://github.com/thorwhalen/hired/tree/HEAD/.claude/agents/hired-alignment-review.md); tools: `Read, Bash, Grep`.

### `hired-company-research`

Researches a hiring company (and the relevant people) for interview/headhunter prep — business, products, market position, recent news/funding, the data-science/AI org, competitors, culture, and likely interview focus. Produces a structured company report and persists it to the candidate knowledge base.

Source: [`.claude/agents/hired-company-research.md`](https://github.com/thorwhalen/hired/tree/HEAD/.claude/agents/hired-company-research.md); tools: `WebSearch, WebFetch, Read, Bash, Grep`.

### `hired-interview-prep`

Produces interview-prep study briefings on the subjects and terminology a candidate should master for a job — focused on what they know LEAST, but every new concept anchored by analogy to the candidate’s OWN experience, concepts, and jargon. Uses the alignment report (to target gaps), the candidate knowledge base (to find anchors), and web research. Persists briefings.

Source: [`.claude/agents/hired-interview-prep.md`](https://github.com/thorwhalen/hired/tree/HEAD/.claude/agents/hired-interview-prep.md); tools: `WebSearch, WebFetch, Read, Bash, Grep`.

### `hired-profile-ingest`

Extracts atomic, provenance-bearing facts about a candidate from raw documents (CVs, bios, resumes, publication lists, LinkedIn exports) for the hired candidate knowledge base. Give it file paths; it returns structured fact records. Read-only on documents; never writes to the repo.

Source: [`.claude/agents/hired-profile-ingest.md`](https://github.com/thorwhalen/hired/tree/HEAD/.claude/agents/hired-profile-ingest.md); tools: `Read, Bash, Grep, Glob`.

### `hired-requirement-analyst`

Classifies one or more job-description requirements against a candidate’s known facts for the hired alignment analyzer. Given requirement text plus relevant candidate facts/synopsis, returns honest per-requirement judgments (match state, match type, level, evidence, closeability, AI-leverage) as structured records. Use to parallelize analysis of a large JD.

Source: [`.claude/agents/hired-requirement-analyst.md`](https://github.com/thorwhalen/hired/tree/HEAD/.claude/agents/hired-requirement-analyst.md); tools: `Read`.

## Instruction files

Files agents read before working in this repository.

- [`.claude/CLAUDE.md`](https://github.com/thorwhalen/hired/tree/HEAD/.claude/CLAUDE.md): read by Claude Code

## Machine-readable documentation

This site publishes the same documentation in forms that fit an agent’s context window:

- [`llms.txt`](https://thorwhalen.github.io/hired/llms.txt): an index of every page with a one-line description ([llms.txt](https://llmstxt.org) format)
- [`hired.md`](https://thorwhalen.github.io/hired/hired.md): the whole documentation as one Markdown file
- `<page>.html.md`: a rendered Markdown twin of every page, advertised from each page’s `<head>` with `<link rel="alternate" type="text/markdown">`
- [`objects.inv`](https://thorwhalen.github.io/hired/objects.inv): the Sphinx inventory: a symbol-to-URL index (`sphobjinv convert plain objects.inv -`)


# api.html.md

# API reference

| [`hired`](_autosummary/hired.html.md#module-hired)   | Public API for the hired package.   |
|-----------------------------------------------------------------------|-------------------------------------|


