尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Purpose: the product front door — what Sartor is, who it's for, and where to go deeper. Also the home page the hosted docs site renders. Audience:
user— the one place all three audiences (job seeker · coach · developer) meet; routes developers onward to the dev-tier homes. Authoritative for: the product positioning, the three-audience cumulative ladder, and at-a-glance orientation + the documentation map. Everything else is cited; the linked canonical home governs on conflict. Type: explanation
Tailor a résumé — and an optional cover letter — to one specific job, on your own machine, without inventing anything about the candidate.
Sartor is a local-first web app that takes a single job description and a person's real career history, then produces a tailored draft — by discovering what's true about them (including real experience left off the résumé, surfaced through a short interview in their own words) and phrasing it for the posting. It runs on your laptop and calls Anthropic's Claude API (application programming interface) for the reasoning; nothing else leaves your machine. It produces documents — it never submits an application or sends an email.
The core discipline: the LLM (large language model) discovers and phrases — it does not invent. No fabricated titles, numbers, or dates. A grounding check in the prompt plus a deterministic "witness" metric measure how much of the output traces back to real material. That's a mechanism and a constraint, not a guarantee a language model can never hallucinate — the full rationale lives in vision.md.
Documentation map. This README orients; the depth lives in single-home docs:
vision.md(intent + scope) ·docs/user/install.md(install + first run) ·docs/user/walkthrough.md(screen-by-screen) ·docs/dev/architecture.md(system + module map + diagrams) ·docs/dev/PRODUCT_SHAPE.md(data model + roadmap ladder) ·docs/dev/system-model.md(the seven pillars + one law) ·docs/governance/(the charter + enforcement) ·AGENTS.md/CLAUDE.md(agent contract + tooling) ·CONTRIBUTING.md(dev loop) ·SECURITY.md(threat model) ·ACCESSIBILITY.md(a11y status). The committed is the synthesized, cited layer the docs assistant reads.
However you found this repo, pick your lane — each points into the doc set above:
CONTRIBUTING.md for the dev loop and branch conventions./prompt-tune, /tune-from-annotations, …) are
Claude Code commands — they need the sartor plugin
(CLAUDE.md); the eval harness itself
(python evals/runner.py …) needs no plugin at all.Three things work against a candidate. A padded history makes claims that fall apart in an interview. A résumé that an applicant tracking system (ATS), the automated screener employers run, can't read never reaches a human. And keeping a tailored copy per application turns into document management — hunting through old files for the one experience point that fits this posting.
Sartor addresses all three. It treats a career history as a corpus, not a pile of files: sourced from the résumés you already have, kept as structured, searchable experience, and grown by clarifying interview questions that surface real work no résumé recorded. Every tailored résumé is drawn from that corpus:
.md / .docx / .pdf); submitting is yours to do.Sartor does one thing — tailor the right résumé for one posting — but three audiences build on each other, each adding one capability to the tier below:
Job seeker Tailor YOUR résumé to one job, grounded in your real history.
└─ + Coach Do that for MANY people — a separate, persistent career file per client.
└─ + Dev EXTEND or TUNE what both experience — new features, better grounding.
Each tier gets everything the tier above it does. A coach is a job seeker with many career files and the tools to run them; a developer makes Sartor better at the job seeker's and the coach's work, or adds new capabilities to it.
| You are… | You build on… | …and add | Section |
|---|---|---|---|
| A job seeker | the core product | — | For job seekers |
| A coach / headhunter | everything a job seeker gets | managing many candidates | For coaches & headhunters |
| A developer | everything both get | extending & tuning the tool itself | For developers |
A sequence of small, inspectable stages — full sequence + diagrams in docs/dev/architecture.md; stage detail in the wiki (pipeline-stages).
1. Job + Analyze — paste the job description; the LLM reports skill match + ATS warnings
2. Clarify (opt) — a short interview surfaces real-but-undocumented experience, in your own words
3. Compose — pin / exclude / add bullets, pick the summary variant, curate skills (scored vs. the JD)
4. Template — pick one of 4 ATS-safe templates with a live, paginated preview
5. Generate — produce the tailored résumé (.docx, .pdf, or .md)
6. Download — review, refine via natural-language notes, download
Optional: + generate a cover letter against the finalized résumé
Two required human gates bracket the work; the clarification interviews between them are optional and cheap. Discover, don't invent: output is grounded in the union of (corpus + clarifying answers + the candidate's own typed edits); a grounding check and a deterministic witness metric measure that it holds — see generation-and-grounding and docs/dev/GROUNDING_METRIC.md.
Prerequisites: git, Python 3.11+, and an
Anthropic API key (console.anthropic.com).
Full prerequisites + OS-specific notes: docs/user/install.md.
From source (works today):
git clone https://github.com/take-tempo-public/sartor
cd sartor
pip install -e .
sartor --setup # one-time: prompts for your key, then Chromium + recall index
sartor # (or: python app.py)
sartor --setup asks for your API key without echoing it and writes .api_key
itself, so the key never enters your shell history. sartor --doctor reports
what your machine supports (Python, OS, key, PDF, recall) and downloads nothing.
Container (Docker or Podman) — not published yet. The image below is the intended distribution path; no version tag has been pushed, so the pull fails today. Use the source install above.
docker run --name sartor -e ANTHROPIC_API_KEY=your-key-here -p 127.0.0.1:5000:5000 \
-v sartor-data:/data \
ghcr.io/take-tempo-public/sartor # podman run … works identically
Then open http://localhost:5000. sartor --setup replaces the manual
python -m playwright install chromium step (it also builds the semantic-recall
index). A pip install sartor / uvx sartor path is planned once the wheel
ships its data files (tracked follow-up).
When the image does ship, name the container and mount the data volume as shown
above — the bare docker run form strands your corpus on the next run, and the
one volume at /data holds everything you own (mount nothing under /app; that
is the program). Full setup (Windows/macOS/Linux),
container data-persistence, cost guidance, and troubleshooting:
docs/user/install.md. Cap spend via
Anthropic usage limits — Sartor
has no built-in budget guard.
Try it without an API key — demo mode serves canned, deterministic AI responses (no key, no network calls, no spend), so you can walk the whole analyze → compose → generate flow before committing a budget:
SARTOR_DEMO=1 sartor # PowerShell: $env:SARTOR_DEMO = "1"; sartor
A persistent banner ("Demo mode — canned AI responses, no API calls") stays visible the whole time, and demo runs never touch the telemetry log or the diagnostics dashboard's cost/latency stats. The canned outputs tell one coherent story (an SRE candidate against an SRE job posting, adapted from the project's synthetic eval fixtures) — they are not tailored to your input. If a real key is present alongside the flag, demo still wins: nothing spends.
Running headless (CI / container / devcontainer)? The bare sartor above
auto-opens a browser and runs Flask's debug reloader — fine for a local
desktop, surprising elsewhere. sartor auto-detects a CI runner or container
and turns both off by default there; SARTOR_NO_BROWSER=1 / FLASK_DEBUG=0
set it explicitly. Details: docs/user/install.md.
Canonical: docs/dev/architecture.md ·
llm-call-catalog. Heavy reasoning
(analyze's synthesis pass, generate, cover letter) runs on Claude Sonnet;
structured selection (analyze's extraction pass, clarify, recommend, extract,
critique) and the docs assistant run on Claude Haiku. Sartor's tailoring
uses the hosted Claude API only — no fine-tuned generation model, nothing
trained on your data. "Tuning" here means prompt, eval, and retrieval
tuning, never model fine-tuning.
The core. Tailor your own résumé to one specific posting, grounded in your real history. Walkthrough: docs/user/walkthrough.md.
.md / .docx / .pdf.The honest catch: you run it yourself (Python + your own API key). A capable tool, not a one-click consumer app.
Everything a job seeker gets — but for every client you carry. (Résumé writers and in-house recruiters prepping candidates, too.) The difference is scale: a job seeker manages one career file; you manage many, and your name is on every résumé you send.
The new capability — managing many candidates. Each client gets a separate, persistent career file you switch between, each compounding independently:
candidate-memory);The professional layer that scale demands:
Honest scope: single-user by design — it's you running many client files locally, not a multi-seat agency platform with a shared team workspace. The threat model is in SECURITY.md; the multi-profile-vs-multi-tenant line is in vision.md.
Sartor is deliberately two things at once: a working résumé product, and a testbed for
reusable capacities (memory, governance, grounding, evaluation) built to be importable beyond
this app. docs/dev/system-model.md is the canonical write-up.
A developer doesn't use Sartor for a different purpose: you make it better at the product's
purposes, add new ones, or lift a capacity out.
Start at Building on Sartor: the dev ladder (install, first green gate, the system map, your first change, why the rules bind) and an index of every dev doc.
/prompt-tune,
/tune-from-annotations), the eval harness and its deterministic metrics
(eval-harness,
evals/TUNING_LOG.md), and the diagnostics console
(docs/dev/diagnostics.md).docs/dev/PRODUCT_SHAPE.md),
the memory substrate in recall/ (docs/dev/memory-architecture.md),
new templates (docs/dev/bundled-templates.md).Note: the résumé generator is not RAG. It puts the whole corpus into the prompt. Retrieval is the doc assistant's mechanism, not the generator's.
Pointers to the canonical homes; the depth lives there.
docs/dev/architecture.md: the pipeline, the
module map, persistence, LLM routing and cost. The deterministic boundary (every LLM call in
analyzer.py) is stated in AGENTS.md.docs/governance/: the charter, and in
enforcement.md the gate-status table saying which rules
are machine-enforced.docs/dev/tooling.md: every hook, guard, slash command,
subagent and skill.CONTRIBUTING.md. python -m scripts.gate is the bar,
and CI runs the same script.Local-first: nothing leaves your computer except the Claude API calls (and the optional opt-in LinkedIn/portfolio scrape). This isn't only policy — it's machine-verified: a test (tests/test_egress_allowlist.py, green at HEAD) confines outbound traffic to exactly two sanctioned classes (the Anthropic API; the opt-in scrape) and fails the build if any module opens a socket elsewhere or a template references an off-box CDN. Configs, source résumés, generated output, the corpus DB, and per-call logs all live gitignored under the repo root. No telemetry, no analytics, no runtime third-party CDN. Full threat model + the file-by-file table: SECURITY.md.
At-a-glance snapshot — the authoritative schedule is docs/dev/RELEASE_ARC.md (+ docs/dev/PRODUCT_SHAPE.md):
.md/.docx/.pdf, the recall substrate + doc-grounded avatar, and the eval/test stack.enforcement.md.An ATS · a job board · a sourcing/scraping platform · an auto-apply bot · a multi-tenant SaaS. It never submits an application or sends an email. The scope is narrow on purpose — see vision.md ("what's out of scope").
docs/wiki/