Skip to content

Jay-00234/dossier

Repository files navigation

Dossier

Most résumé tools start from a prompt. Dossier starts from your experiences.

CI License: MIT Made with Claude Code

One-page resume rendered from templates/resume/standard.tex — synthetic candidate Pat Doe

Above: a one-page sample rendered from templates/resume/standard.tex using a synthetic candidate. Source content lives in examples/sample_resume_content.json; the rendered .tex is at examples/sample_resume.tex.

Dossier is an experience-first application material generator. Instead of regenerating your résumé from scratch every time you apply, Dossier keeps your experiences as structured, first-class records in a local SQLite store — your dossier — and each application is a retrieval + selection + rewriting pass against it. Bullets you rewrite for one application can be promoted back into the dossier, so the record sharpens with every run.

Dossier runs inside Claude Code. Claude is the agent — it parses the brief, matches experiences, writes bullets. Python is just a thin I/O layer over SQLite and file rendering. There are no LLM calls from Python and no anthropic dependency.

CLAUDE.md is the agent rulebook for Claude Code. If you're not using Claude Code, you can skip it — the README, DESIGN.md, and the agents/*.md workflow specs are enough on their own.

What Dossier is not

  • Not a prompt-first generator. Your experience record is the source of truth, not the prompt. The same dossier serves every application.
  • Not a hosted service. Everything runs locally. Your data lives in a SQLite file on your own machine (./dossier.db by default).
  • Not an auto-apply bot. Dossier produces drafts. You review, edit, and submit.

How it works

                       ┌────────────────────┐
                       │  dossier.db        │
              intake ─►│  experience table  │◄── sync_back
           (add one)   │  profile  table    │   (rewrites → store)
                       └──────────┬─────────┘
                                  │ read
                                  ▼
       brief ──►  matcher ──► match_report.json
                                  │
                ┌─────────────────┼─────────────────┐
                ▼                 ▼                 ▼
             resume             prose               qa
             (.tex)            (.docx)         (answers.md)

V1 is English-only. Bilingual / CN support is on the V2 roadmap (DESIGN.md §13).

Each box is an independent agent — a workflow document under agents/ that Claude follows when you trigger it. Agents never chain automatically: one user turn, one agent. You decide when to matcher, when to resume, when to sync_back.

The agents

Agent Trigger Produces
intake "save this experience" New row in the experience table
matcher "match this JD" / "match this scholarship call" match_report.json (selected experiences + document strategy)
resume "write the resume" resume_<lang>.tex via a LaTeX template
resume_fix "fix this compile error" Edits on an existing .tex or template
prose "write a cover letter / SOP / motivation letter" *.docx
qa "answer the application form" answers_<lang>.md
sync_back "promote these bullets back to the dossier" Updated bullets_en on source experiences

Quick Start

Prerequisites

  • Python 3.11+
  • Claude Code CLI
  • An Overleaf account (for compiling .tex output — no local LaTeX toolchain required)

Setup

# 1. Clone and install
git clone https://github.com/Jay-00234/dossier.git
cd dossier
python -m venv .venv && source .venv/bin/activate
pip install -e .

# 2. Open Claude Code in this directory
claude

The first write (intake or profile) creates ./dossier.db automatically. Override the path by setting DOSSIER_DB_PATH in .env if you want the file somewhere else (e.g. inside a synced folder for backup).

Try it without committing your own data

If you'd rather see a full run before feeding Dossier your real experiences, examples/ contains a synthetic experience record and a job description. The examples/README.md walks through loading them into a throwaway DB and running the matcher end-to-end.

First run

In the Claude Code conversation, drive the agents explicitly. Two equivalent trigger styles:

Natural language:

intake this experience:
  <paste messy narrative — CN or EN, either is fine>

match this JD:
  <paste job description>

run resume

run prose as cover letter

Slash commands (defined in .claude/commands/):

/intake
  <paste messy narrative>

/matcher
  <paste JD>

/resume

/prose cover letter

Each agent writes its artifacts to output/<slug>/, where <slug> is <org>_<opportunity>_<YYYYMMDD>. Compile .tex on Overleaf; open .docx anywhere.

Project structure

dossier/
├── CLAUDE.md                 # Project instructions Claude reads on startup
├── agents/                   # Workflow documents Claude follows
│   ├── intake.md
│   ├── matcher.md
│   ├── resume.md
│   ├── resume_fix.md
│   ├── prose.md
│   ├── qa.md
│   ├── sync_back.md
│   └── references/           # Style notes (e.g. cover_letter_patterns.md)
├── dossier.db                # SQLite store — source of truth (gitignored)
├── matcher_config.yaml       # Matcher weights / thresholds / rules (DESIGN.md §8.2)
├── src/
│   ├── cache.py              # JSON-snapshot layer in front of SQLite
│   ├── storage/              # SQLite store + canonical dataclasses
│   │   ├── models.py         # Experience / Profile / Evidence
│   │   ├── base.py           # ExperienceStore / ProfileStore protocols
│   │   ├── sqlite_store.py
│   │   └── schema.sql
│   └── renderers/
│       ├── latex.py          # Fill .tex templates from content JSON
│       ├── typst_render.py   # Fill .typ templates (local `typst compile`)
│       └── docx.py           # Build prose .docx from content JSON
├── scripts/                  # Thin CLI wrappers around src/
│   ├── show_tags.py
│   ├── list_experiences.py
│   ├── get_experiences.py
│   ├── write_experience.py
│   ├── update_experience.py
│   ├── write_profile.py
│   ├── refresh_cache.py
│   ├── render_resume.py
│   └── render_cover_letter.py
├── templates/
│   └── resume/               # Parameterized templates
│       ├── standard.tex      # default EN, pdflatex on Overleaf
│       ├── standard_dba.tex  # DBA-application variant
│       └── standard.typ      # Typst version of the default template
├── examples/                 # Synthetic experience + JD pair for first-run dogfooding
├── output/                   # Generated material, one folder per application (gitignored)
└── .cache/                   # JSON snapshots exported from SQLite (gitignored)

Architecture: Claude is the agent, Python is I/O

Every script in scripts/ is a pure wrapper around the local SQLite store or the filesystem: read tags, write an experience, list rows, render a template. No LLM calls, no anthropic dependency. The intelligence — parsing a brief, choosing which experiences to surface, writing bullets — happens in the Claude Code conversation.

This split has two consequences worth knowing:

  1. The agents/*.md files are workflow instructions for Claude, not system prompts shipped to an API. You can edit them and Claude will pick up your changes in the next conversation.
  2. Agents are decoupled by design. Re-running matcher never triggers resume. Re-running resume reads the existing match_report.json as-is and does not regenerate it. The user orchestrates; Claude does not.

The decoupling rules are spelled out in CLAUDE.md and are enforced by convention (Claude reads them on every startup).

Templates

Résumé templates live in templates/resume/ with %%MARKER%% placeholders that src/renderers/latex.py substitutes. The LaTeX templates are parameter-filled, not LLM-generated — Claude writes the content JSON, and the renderer merges it into a pre-validated .tex shell. This keeps the preamble and macros stable across runs.

The default template (standard.tex) is derived from Jake Gutierrez's "Jake's Resume" style via sb2nov/resume (MIT) with an intermediate adaptation by Jay. Full attribution and the upstream license text live in THIRD_PARTY_NOTICES.md.

TBD. Template variants (standard.tex / standard_dba.tex / standard.typ), the Typst-vs-LaTeX render path, and language-format conventions are all still being designed. See the "TBD" section in CLAUDE.md for specifics.

Tech stack

  • Runtime: Python 3.11+
  • Storage: SQLite (stdlib sqlite3)
  • Rendering: python-docx for prose, string-template substitution for LaTeX
  • Validation: pydantic
  • Agent: Claude Code

Disclaimer

Dossier is a local, open-source tool, not a hosted service.

  • Your data stays with you. Experiences live in ./dossier.db on your own machine. Nothing is uploaded to a third party except the Claude API calls Claude Code itself makes on your behalf.
  • AI-generated content needs review. Bullets, cover letters, and translations may contain inaccuracies or hallucinations. Always proofread before submitting to an employer, school, or funder.
  • No guarantees. The authors are not responsible for application outcomes, admissions decisions, or employment results.

License

MIT. Third-party material bundled in this repository (résumé templates) is attributed in THIRD_PARTY_NOTICES.md.

About

Experience-first application material generator. Local SQLite store, Claude Code as the agent.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors