Apply: Resume and Posting to Application Package
WorkflowTurns a master resume and a job posting into a tailored, ATS-optimized resume, a cover letter, and an honest match-gap report, refined by a screen/fix loop. Produces documents; never auto-submits.
Usage
echo "<your request>" | octomind workflow apply Reads your request from stdin. Add --dry-run to validate and print the plan without
running any steps.
Pipeline
-
Prepare an intake brief from the request below. Read the master resume (file path or pasted text) and the job posting (file path, fetched URL, or pasted text). The brief carries: - <master_resume> — the file path verbat…
-
If the intake below is a single `INTAKE-BLOCKED:` line, output that exact line and nothing else. Otherwise produce, from the intake brief (read the master resume from the file <master_resume> names, or use its pasted te…
- 3 screen Loop
- fix coach:resume
If the draft below is a single `INTAKE-BLOCKED:` line, output that exact line and nothing else. Otherwise apply the screener's findings to the resume, cover letter, and report — criticals first, without reintroducing an…
- audit coach:screener
If the documents below are a single `INTAKE-BLOCKED:` line, end your whole response with exactly `SCREEN-PASS` (nothing to audit; let the run finish and report the block). Nothing else. Otherwise audit the tailored resu…
-
If the final documents below are a single `INTAKE-BLOCKED:` line, write nothing to disk — tell the user what couldn't be read (quote the line) and that no package was produced. Stop there. Otherwise the loop is finished…
Definition
# Title: Apply: Resume and Posting to Application Package
#
# Public workflow: turn a master resume plus a specific job posting into a
# ready-to-submit application PACKAGE — an ATS-optimized, country-correct
# tailored resume, a matching cover letter, and an honest match+gap report.
# It does NOT submit anything: the deliverable is documents for the human to
# send. Auto-applying violates job-board terms, needs logins/captcha, and
# mass-identical submissions hurt callbacks — so the product is the package,
# and the human hits submit.
#
# Shape (same evaluator-optimizer pattern as localize / promote):
# intake (resolve resume + posting + destinations, detect target market) ->
# tailor (grounded, ATS-optimized, market-adapted resume + cover letter) ->
# screen loop (fix <-> audit until the screener passes) -> deliver.
#
# File-first: intake resolves a destination per document (the path the request
# names, else `inline`). A document with a destination is written by tailor,
# edited in-place by fix, and read back by the screener — it never round-trips
# through the conversation. Inline documents are carried in the conversation
# and returned by deliver.
#
# Grounding contract: every keyword, metric, title, date, and skill must
# trace to the master resume — no invented experience. Keyword coverage is
# maximized only within what's true; genuine gaps are reported honestly, never
# faked. The screener's truthfulness gate fails the run on any fabrication,
# regardless of ATS match score.
#
# Roles: `coach:resume` reads/tailors/writes/fixes/delivers the documents;
# `coach:screener` is the independent auditor (ATS match + truthfulness +
# convention + letter quality). Knowledge lives in the ats-optimization,
# resume-conventions, and cover-letter skills.
#
# Note: `max_iterations = 3` ceiling (quality peaks early). `retries = 4`
# guards transient provider/network errors.
#
# Source paths: the master resume and job posting are file paths or pasted
# text (reliable), or a job-posting URL (works when the runtime can fetch it;
# otherwise intake halts rather than inventing the posting).
#
# Input shape: point at the resume and the posting; optionally the target
# country, destinations, and any specifics. Example:
# Tailor my resume and write a cover letter for this job.
# Master resume: ./resume.md
# Job posting: https://example.com/careers/senior-engineer
#
# Public roles only.
name = "apply"
description = "Turns a master resume and a job posting into a tailored, ATS-optimized resume, a cover letter, and an honest match-gap report, refined by a screen/fix loop. Produces documents; never auto-submits."
# ── 1. Intake — read resume + posting, capture both, detect target market ───
[[steps]]
name = "intake"
role = "coach:resume"
session = "fresh"
retries = 4
prompt = """
Prepare an intake brief from the request below. Read the master resume (file
path or pasted text) and the job posting (file path, fetched URL, or pasted
text). The brief carries:
- <master_resume> — the file path verbatim when the resume is a file (later
steps read it from disk — do NOT reproduce its content); the full text
verbatim when it was pasted. This is the ONLY ground truth for what's true
about the candidate.
- <job_posting> — the posting, verbatim (it may have come from a URL that
later steps cannot fetch), plus the extracted signals: exact job title,
15–20 priority keywords/skills, and required-vs-preferred qualifications.
- Target market: detect it from the posting's location/company (e.g. US, UK,
Germany, EU) so later steps apply the right resume convention; if genuinely
ambiguous, note your best inference and why.
- <destinations> — one line per document (resume, cover letter, report): the
path the request names for it, otherwise the word `inline`. Never invent a
path — an unstated destination is `inline`, not a guess.
HARD STOP: if the master resume or the job posting can't be read — missing or
unreadable file, or a URL you have no tool to fetch — do NOT invent a
candidate history or a job's requirements. Output exactly this one line and
nothing else: `INTAKE-BLOCKED: <what> — <reason>`.
Do not tailor or write anything yet. No meta-commentary.
<request>
{{input}}
</request>
"""
# ── 2. Tailor — grounded, ATS-optimized, market-adapted draft ───────────────
[[steps]]
name = "tailor"
role = "coach:resume"
session = "fresh"
retries = 4
prompt = """
If the intake below is a single `INTAKE-BLOCKED:` line, output that exact line
and nothing else.
Otherwise produce, from the intake brief (read the master resume from the
file <master_resume> names, or use its pasted text):
1. A tailored resume — mirror the posting's language and priorities per
`ats-optimization`, but ONLY using experience, skills, titles, dates, and
numbers present in the master resume. Quantified achievement bullets, target
job title in the summary, skills reordered to the posting. Adapt document
name / length / photo / GDPR / dates to the target market per
`resume-conventions`.
2. A cover letter per `cover-letter` — grounded in the tailored resume and the
specific company/role, human (content-voice), no template tells.
3. A match + gap report — keyword coverage, what maps to real experience, and
the requirements the candidate genuinely doesn't meet (honest options, no
fabricated lines).
Truthfulness gate: nothing on the resume or letter that the master resume or
the candidate's input doesn't support. No invented experience, no keyword
stuffing, no auto-submitting.
Delivery, per document: if the intake's <destinations> lists a path, write
the document there now — the file's new content IS the document, whole
(in-place, git-aware; no `.new`, `.bak`, or suffixed copies). If it is
`inline`, output the document in the conversation instead.
<intake>
{{intake}}
</intake>
Output three delimited blocks — `<resume>`…`</resume>`,
`<cover_letter>`…`</cover_letter>`, `<report>`…`</report>` — where a written
document's block holds only `written: <path>` and an inline document's block
holds the full text. Never paste a written file's content into the output. No
meta-commentary.
"""
# ── 3. Screen loop — fix <-> audit until the screener passes ─────────────────
[[steps]]
name = "screen"
loop = true
max_iterations = 3
exit_when = { output = "audit", matches = '(?m)^SCREEN-PASS' }
[[steps.run]]
name = "fix"
role = "coach:resume"
session = "continue"
retries = 4
prompt = """
If the draft below is a single `INTAKE-BLOCKED:` line, output that exact line
and nothing else.
Otherwise apply the screener's findings to the resume, cover letter, and
report — criticals first, without reintroducing anything already fixed and
without ever breaking the truthfulness gate (never add a keyword or claim the
master resume doesn't support to raise the match score — report it as a gap
instead). A document with a destination path in the intake lives in that
file: read it, edit it in-place (git-aware, no suffixed copies), and report
what changed. An `inline` document is edited in the conversation and output in
full. On the first round, before any findings exist, self-review against
`ats-optimization`, `resume-conventions`, and `cover-letter` and fix what they
flag.
<intake>
{{intake}}
</intake>
<draft>
{{tailor}}
</draft>
Output the three blocks again — `<resume>`…`</resume>`,
`<cover_letter>`…`</cover_letter>`, `<report>`…`</report>` — where a file
document's block holds `edited: <path>` (or `unchanged: <path>`) plus a short
list of what changed, and an inline document's block holds the full edited
text. Never paste a file's content into the output. No meta-commentary.
"""
[[steps.run]]
name = "audit"
role = "coach:screener"
session = "fresh"
retries = 4
prompt = """
If the documents below are a single `INTAKE-BLOCKED:` line, end your whole
response with exactly `SCREEN-PASS` (nothing to audit; let the run finish and
report the block). Nothing else.
Otherwise audit the tailored resume + cover letter against the master resume
(read the file the intake's <master_resume> names, or use its pasted text),
the intake's <job_posting>, and target market, per your role and the
ats-optimization / resume-conventions / cover-letter skills. Read each
document from its destination file listed in the intake — that file is the
draft under audit; the fix report below only says what changed. An `inline`
document's text is the block in the fix report. Run the truthfulness gate
FIRST: any claim, metric, title, date, employer, degree, or skill not
supported by the master resume is a CRITICAL fabrication finding. Then ATS
match, convention correctness, and cover-letter quality.
<intake>
{{intake}}
</intake>
<documents>
{{fix}}
</documents>
List findings severity-ranked (CRITICAL / MAJOR / MINOR) with the axis, the
quoted line, why it matters, and the fix direction; then the coverage report.
Close with exactly one line — `SCREEN-PASS` (ATS match in range, zero CRITICAL
or MAJOR findings, conventions correct, no fabrication) or `SCREEN-FAIL`. A
single fabrication finding forces SCREEN-FAIL regardless of match score.
Nothing after that line. Read-only — never edit files.
"""
# ── 4. Deliver — inline documents + summary; file documents are done ────────
[[steps]]
name = "deliver"
role = "coach:resume"
session = "fresh"
retries = 4
prompt = """
If the final documents below are a single `INTAKE-BLOCKED:` line, write nothing
to disk — tell the user what couldn't be read (quote the line) and that no
package was produced. Stop there.
Otherwise the loop is finished. Every document with a destination path in
the intake is already on disk — tailor wrote it and each fix round edited it
in-place — so write nothing, re-edit nothing, and make no editorial decisions
of your own. For each `inline` document, output its final block from
`<final>` verbatim, whole. Never submit or post the application anywhere —
the human submits.
<intake>
{{intake}}
</intake>
<final>
{{fix}}
</final>
<final_audit>
{{audit}}
</final_audit>
After delivering, give a brief summary: the ATS match coverage, the top
honest gaps the candidate should be aware of, the final screen verdict, and
where each artifact landed (file path or inline).
"""