skilldrop-cli 0.16.6 → 0.16.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/catalogue.json +11 -1
- package/model-routing.json +16 -0
- package/package.json +1 -1
- package/packs/ai-engineering/skills/ai-usage-policy/evals/evals.json +30 -0
- package/packs/ai-engineering/skills/ai-usage-policy/evals/files/2/data-handling-sheet.md +18 -0
- package/packs/ai-engineering/skills/ai-usage-policy/evals/files/2/it-notes.md +31 -0
- package/packs/ai-engineering/skills/ai-usage-policy/evals/files/2/md-email.md +29 -0
- package/packs/api-builder/skills/tool-use-schema-writer/evals/evals.json +29 -0
- package/packs/api-builder/skills/tool-use-schema-writer/evals/files/2/book_appointment.ts +64 -0
- package/packs/career/loops/apply/LOOP.md +97 -0
- package/packs/career/loops/apply/evals/eval_queries.json +9 -0
- package/packs/career/loops/apply/evals/evals.json +27 -0
- package/packs/career/loops/apply/loop.json +52 -0
- package/packs/career/pack.json +77 -0
- package/packs/career/skills/application-form-answers/SKILL.md +146 -0
- package/packs/career/skills/application-form-answers/evals/eval_queries.json +34 -0
- package/packs/career/skills/application-form-answers/evals/evals.json +103 -0
- package/packs/career/skills/application-form-answers/evals/files/1/form.md +17 -0
- package/packs/career/skills/application-form-answers/evals/files/1/posting.md +20 -0
- package/packs/career/skills/application-form-answers/evals/files/1/resume.md +32 -0
- package/packs/career/skills/application-form-answers/evals/files/2/form.md +15 -0
- package/packs/career/skills/application-form-answers/evals/files/2/posting.md +21 -0
- package/packs/career/skills/application-form-answers/evals/files/2/resume.md +32 -0
- package/packs/career/skills/application-form-answers/evals/files/4/form.md +14 -0
- package/packs/career/skills/application-form-answers/evals/files/4/posting.md +25 -0
- package/packs/career/skills/application-form-answers/evals/files/4/resume.md +29 -0
- package/packs/career/skills/application-form-answers/evals/files/5/form.md +15 -0
- package/packs/career/skills/application-form-answers/evals/files/5/posting.md +18 -0
- package/packs/career/skills/application-form-answers/evals/files/5/resume.md +23 -0
- package/packs/career/skills/application-form-answers/evals/files/6/form.md +11 -0
- package/packs/career/skills/application-form-answers/evals/files/6/posting.md +28 -0
- package/packs/career/skills/application-form-answers/evals/files/6/resume.md +35 -0
- package/packs/career/skills/application-form-answers/evals/files/7/form.md +11 -0
- package/packs/career/skills/application-form-answers/evals/files/7/posting.md +19 -0
- package/packs/career/skills/application-form-answers/evals/files/7/resume.md +26 -0
- package/packs/career/skills/application-form-answers/manifest.json +31 -0
- package/packs/career/skills/cover-letter/SKILL.md +132 -0
- package/packs/career/skills/cover-letter/evals/eval_queries.json +34 -0
- package/packs/career/skills/cover-letter/evals/evals.json +100 -0
- package/packs/career/skills/cover-letter/evals/files/1/posting.md +28 -0
- package/packs/career/skills/cover-letter/evals/files/1/resume.md +35 -0
- package/packs/career/skills/cover-letter/evals/files/2/posting.md +20 -0
- package/packs/career/skills/cover-letter/evals/files/2/resume.md +32 -0
- package/packs/career/skills/cover-letter/evals/files/4/posting.md +19 -0
- package/packs/career/skills/cover-letter/evals/files/4/resume.md +26 -0
- package/packs/career/skills/cover-letter/evals/files/5/posting.md +21 -0
- package/packs/career/skills/cover-letter/evals/files/5/resume.md +32 -0
- package/packs/career/skills/cover-letter/evals/files/6/posting.md +25 -0
- package/packs/career/skills/cover-letter/evals/files/6/resume.md +29 -0
- package/packs/career/skills/cover-letter/evals/files/7/posting.md +18 -0
- package/packs/career/skills/cover-letter/evals/files/7/resume.md +23 -0
- package/packs/career/skills/cover-letter/manifest.json +37 -0
- package/packs/career/skills/cover-letter/scripts/claim_check.py +250 -0
- package/packs/career/skills/job-fit-analysis/SKILL.md +152 -0
- package/packs/career/skills/job-fit-analysis/evals/eval_queries.json +34 -0
- package/packs/career/skills/job-fit-analysis/evals/evals.json +102 -0
- package/packs/career/skills/job-fit-analysis/evals/files/1/posting.md +28 -0
- package/packs/career/skills/job-fit-analysis/evals/files/1/resume.md +35 -0
- package/packs/career/skills/job-fit-analysis/evals/files/2/posting.md +20 -0
- package/packs/career/skills/job-fit-analysis/evals/files/2/resume.md +32 -0
- package/packs/career/skills/job-fit-analysis/evals/files/4/posting.md +25 -0
- package/packs/career/skills/job-fit-analysis/evals/files/4/resume.md +29 -0
- package/packs/career/skills/job-fit-analysis/evals/files/5/posting.md +18 -0
- package/packs/career/skills/job-fit-analysis/evals/files/5/resume.md +23 -0
- package/packs/career/skills/job-fit-analysis/evals/files/6/linkedin-about.txt +5 -0
- package/packs/career/skills/job-fit-analysis/evals/files/6/posting.md +25 -0
- package/packs/career/skills/job-fit-analysis/evals/files/6/resume.md +35 -0
- package/packs/career/skills/job-fit-analysis/evals/files/7/resume.md +32 -0
- package/packs/career/skills/job-fit-analysis/manifest.json +31 -0
- package/packs/career/skills/resume-tailor/SKILL.md +144 -0
- package/packs/career/skills/resume-tailor/evals/eval_queries.json +34 -0
- package/packs/career/skills/resume-tailor/evals/evals.json +133 -0
- package/packs/career/skills/resume-tailor/evals/files/1/posting.md +26 -0
- package/packs/career/skills/resume-tailor/evals/files/1/resume.md +32 -0
- package/packs/career/skills/resume-tailor/evals/files/2/posting.md +19 -0
- package/packs/career/skills/resume-tailor/evals/files/2/resume.md +26 -0
- package/packs/career/skills/resume-tailor/evals/files/3/posting.md +21 -0
- package/packs/career/skills/resume-tailor/evals/files/3/resume.md +32 -0
- package/packs/career/skills/resume-tailor/evals/files/4/posting.md +28 -0
- package/packs/career/skills/resume-tailor/evals/files/4/resume.md +35 -0
- package/packs/career/skills/resume-tailor/evals/files/5/posting.md +20 -0
- package/packs/career/skills/resume-tailor/evals/files/5/resume.md +32 -0
- package/packs/career/skills/resume-tailor/evals/files/6/posting.md +25 -0
- package/packs/career/skills/resume-tailor/evals/files/6/resume.md +29 -0
- package/packs/career/skills/resume-tailor/evals/files/7/posting.md +18 -0
- package/packs/career/skills/resume-tailor/evals/files/7/resume.md +23 -0
- package/packs/career/skills/resume-tailor/evals/files/8/posting.md +25 -0
- package/packs/career/skills/resume-tailor/evals/files/8/resume.typ +31 -0
- package/packs/career/skills/resume-tailor/evals/files/9/linkedin-about.txt +5 -0
- package/packs/career/skills/resume-tailor/evals/files/9/posting.md +25 -0
- package/packs/career/skills/resume-tailor/evals/files/9/resume.md +35 -0
- package/packs/career/skills/resume-tailor/manifest.json +37 -0
- package/packs/career/skills/resume-tailor/scripts/claim_check.py +250 -0
- package/packs/data-analytics/skills/metric-definition/evals/evals.json +30 -0
- package/packs/data-analytics/skills/metric-definition/evals/files/2/tables.md +42 -0
- package/packs/data-analytics/skills/metric-definition/evals/files/2/thread.md +40 -0
- package/packs/dev-team/skills/contribution-wizard/evals/evals.json +29 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/AGENTS.md +9 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/CATALOG.md +18 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/CONTRIBUTING.md +45 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/OWNERS.md +7 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/detention-claim-letter/INSTRUCTIONS.md +20 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/detention-claim-letter/skill.yaml +11 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/detention-claim-letter/tests/cases.yaml +25 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/rate-con-extractor/INSTRUCTIONS.md +20 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/rate-con-extractor/skill.yaml +8 -0
- package/packs/dev-team/skills/contribution-wizard/evals/files/2/skills/rate-con-extractor/tests/cases.yaml +32 -0
- package/packs/dev-team/skills/devils-advocate/evals/evals.json +29 -0
- package/packs/dev-team/skills/devils-advocate/evals/files/2/signups.py +116 -0
- package/packs/dev-team/skills/devils-advocate/evals/files/2/test_signups.py +69 -0
- package/packs/dev-team/skills/release-notes/evals/evals.json +29 -0
- package/packs/dev-team/skills/release-notes/evals/files/2/commits.txt +35 -0
- package/packs/research/skills/source-synthesis/evals/evals.json +30 -0
- package/packs/research/skills/source-synthesis/evals/files/2/badge-data.md +27 -0
- package/packs/research/skills/source-synthesis/evals/files/2/director-email.md +16 -0
- package/packs/research/skills/source-synthesis/evals/files/2/exit-interviews.md +17 -0
- package/packs/research/skills/source-synthesis/evals/files/2/practice-weekly-article.md +21 -0
- package/packs/research/skills/source-synthesis/evals/files/2/staff-survey-summary.md +41 -0
- package/packs/solution-architect/skills/db-schema-design/evals/evals.json +29 -0
- package/packs/solution-architect/skills/db-schema-design/evals/files/2/current_tables.sql +29 -0
- package/packs/solution-architect/skills/db-schema-design/evals/files/2/notes.md +53 -0
- package/packs/solution-architect/skills/design-doc/evals/evals.json +29 -0
- package/packs/solution-architect/skills/design-doc/evals/files/2/brief.md +18 -0
- package/packs/solution-architect/skills/design-doc/evals/files/2/eng-notes.md +30 -0
- package/packs/solution-architect/skills/tech-comparison-matrix/evals/evals.json +29 -0
- package/packs/solution-architect/skills/tech-comparison-matrix/evals/files/2/requirements.md +20 -0
- package/packs/solution-architect/skills/tech-comparison-matrix/evals/files/2/vendor-notes.md +29 -0
- package/packs/sre-oncall/skills/postmortem-generator/evals/evals.json +30 -0
- package/packs/sre-oncall/skills/postmortem-generator/evals/files/2/pager-export.txt +22 -0
- package/packs/sre-oncall/skills/postmortem-generator/evals/files/2/slack-thread.txt +28 -0
- package/packs/stakeholder-comms/skills/guide-builder/evals/evals.json +29 -0
- package/packs/stakeholder-comms/skills/guide-builder/evals/files/2/api-notes.md +44 -0
- package/packs/stakeholder-comms/skills/guide-builder/evals/files/2/sample-booking.json +19 -0
- package/profiles.json +2 -2
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
LEO TANAKA
|
|
2
|
+
Edinburgh | leo.tanaka@example.com | 07700 900271
|
|
3
|
+
|
|
4
|
+
Sous Chef, The Larder at Queensgate (80-cover restaurant), Edinburgh
|
|
5
|
+
May 2022 - present
|
|
6
|
+
- Run the kitchen on the head chef's two days off each week.
|
|
7
|
+
- Lead a brigade of 6 on service.
|
|
8
|
+
- Write and cost the weekly specials; do the fish and vegetable orders.
|
|
9
|
+
- Trained 3 commis chefs, one now a chef de partie.
|
|
10
|
+
- Keep the allergen matrix up to date for every menu change.
|
|
11
|
+
- Environmental health inspection in 2025: rated 5.
|
|
12
|
+
|
|
13
|
+
Chef de Partie, Harbour Rooms Hotel, Leith
|
|
14
|
+
March 2019 - April 2022
|
|
15
|
+
- Ran the sauce section; covered banqueting for weddings in summer.
|
|
16
|
+
|
|
17
|
+
Commis Chef, Harbour Rooms Hotel, Leith
|
|
18
|
+
August 2017 - March 2019
|
|
19
|
+
|
|
20
|
+
TRAINING
|
|
21
|
+
SVQ Level 3 Professional Cookery, Edinburgh College, 2019
|
|
22
|
+
Level 2 Food Safety and Hygiene for Catering, renewed 2024
|
|
23
|
+
Allergen awareness training, 2024
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cover-letter",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Write a cover letter for one job from the person's resume and the posting: under a page, opening on the strongest evidence for the role, two or three specifics matched to what the employer asked for, and no enthusiasm, company facts or experience the person didn't supply. A script lists every figure and name in the letter that their own material doesn't contain. Works for any occupation and level. Use when the user says \"write a cover letter for this job\", \"draft a covering letter\", \"write the cover note for my application\", or needs an application email to go with a resume.",
|
|
5
|
+
"entrypoint": "SKILL.md",
|
|
6
|
+
"deps": {
|
|
7
|
+
"npm": [],
|
|
8
|
+
"pip": []
|
|
9
|
+
},
|
|
10
|
+
"env": {
|
|
11
|
+
"required": [],
|
|
12
|
+
"optional": []
|
|
13
|
+
},
|
|
14
|
+
"related": [
|
|
15
|
+
"job-fit-analysis",
|
|
16
|
+
"output-hygiene",
|
|
17
|
+
"resume-tailor"
|
|
18
|
+
],
|
|
19
|
+
"tags": [
|
|
20
|
+
"cover-letter",
|
|
21
|
+
"job-application",
|
|
22
|
+
"resume",
|
|
23
|
+
"career",
|
|
24
|
+
"job-search",
|
|
25
|
+
"writing"
|
|
26
|
+
],
|
|
27
|
+
"permissions": {
|
|
28
|
+
"network": [],
|
|
29
|
+
"commands": [],
|
|
30
|
+
"files": "named-paths",
|
|
31
|
+
"notes": "Reads the draft, source and posting files it is given. Writes nothing."
|
|
32
|
+
},
|
|
33
|
+
"model": {
|
|
34
|
+
"tier": "standard",
|
|
35
|
+
"rationale": "A short letter from supplied facts, with a script listing every figure and name the person's material doesn't contain."
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""List what a tailored resume or cover letter says that the candidate's own material doesn't.
|
|
3
|
+
|
|
4
|
+
python3 claim_check.py DRAFT --source RESUME [--source NOTES ...] [--posting POSTING] [--json]
|
|
5
|
+
|
|
6
|
+
DRAFT is the text you are about to send. Each --source is something the candidate wrote or
|
|
7
|
+
told you: the original resume, notes from the conversation. --posting is the job posting.
|
|
8
|
+
|
|
9
|
+
It reports four kinds of finding, each with the line it is on:
|
|
10
|
+
|
|
11
|
+
number a figure in the draft that no source contains ("35%", "$2M", "team of 8")
|
|
12
|
+
name a named thing in the draft that no source contains: a tool, an employer, a
|
|
13
|
+
certification, a degree ("Kubernetes", "Epic", "Green Belt")
|
|
14
|
+
combination capitalised words that each appear in a source but never together
|
|
15
|
+
("Senior Manager" when the source has "Senior Analyst" and "Office Manager")
|
|
16
|
+
borrowed wording the draft shares with the posting and no source uses. Fine when the
|
|
17
|
+
source shows the same thing in other words; a false claim when it doesn't.
|
|
18
|
+
|
|
19
|
+
A name or number that the posting contains is marked "in posting": right when the draft is
|
|
20
|
+
talking about the employer, wrong when it is claimed as the candidate's own.
|
|
21
|
+
|
|
22
|
+
It reads text, so it cannot tell a true claim from a false one. It tells you where to look.
|
|
23
|
+
Exit status: 0 nothing found, 1 findings, 2 a file could not be read. Standard library only.
|
|
24
|
+
"""
|
|
25
|
+
import argparse
|
|
26
|
+
import json
|
|
27
|
+
import re
|
|
28
|
+
import sys
|
|
29
|
+
|
|
30
|
+
MULT = {"k": 1e3, "thousand": 1e3, "m": 1e6, "mm": 1e6, "million": 1e6,
|
|
31
|
+
"bn": 1e9, "b": 1e9, "billion": 1e9}
|
|
32
|
+
NUMBER = re.compile(r"(?<![\w.])(\d[\d,]*(?:\.\d+)?)(?:(k|mm|m|bn|b)\b|\s?(thousand|million|billion)\b)?"
|
|
33
|
+
r"(\s?%|\s?percent\b|\s?per cent\b)?", re.I)
|
|
34
|
+
WORD = re.compile(r"(?<![A-Za-z0-9])\.?[A-Za-z][A-Za-z0-9+#']*(?:\.[A-Za-z0-9]+)*")
|
|
35
|
+
LIST_MARK = re.compile(r"^\s*(?:[-*•–>]+|\d+[.)]|#+|\|)\s*")
|
|
36
|
+
LINK = re.compile(r"\[([^\]]*)\]\([^)]*\)")
|
|
37
|
+
SUFFIXES = ("ations", "ation", "ments", "ment", "ings", "ing", "ers", "ies", "ed", "er", "es", "s", "ly")
|
|
38
|
+
|
|
39
|
+
# Words that start a line or a sentence with a capital letter and name nothing.
|
|
40
|
+
PLAIN = set("""
|
|
41
|
+
a an and are as at be been both but by for from had has have he her his i if in into is it its
|
|
42
|
+
me my no not of on or our she so that the their them then there these they this to up us was
|
|
43
|
+
we were what when where which who why with you your dear sincerely regards kind best yours
|
|
44
|
+
faithfully hiring manager team committee recruiter sir madam re subject date enclosed
|
|
45
|
+
summary profile objective experience employment work history education skills tools
|
|
46
|
+
certifications certification qualifications training projects awards languages interests
|
|
47
|
+
references available request professional career key core technical additional other
|
|
48
|
+
volunteering volunteer contact details achievements highlights about present current
|
|
49
|
+
january february march april may june july august september october november december
|
|
50
|
+
jan feb mar apr jun jul aug sep sept oct nov dec monday tuesday wednesday thursday friday
|
|
51
|
+
saturday sunday full part time application applying while although though because since
|
|
52
|
+
during after before however also please thank thanks between over across within having most each every one two three
|
|
53
|
+
""".split())
|
|
54
|
+
DATE_LINE = re.compile(r"^\s*(?:\d{1,2}(?:st|nd|rd|th)?\s+)?[A-Z][a-z]{2,8}\.?\s+(?:\d{1,2}(?:st|nd|rd|th)?,?\s+)?\d{4}\s*$")
|
|
55
|
+
# The joining words allowed inside a capitalised phrase: "Head of Geography".
|
|
56
|
+
JOINERS = {"of", "and", "for", "the", "in", "at", "&", "de"}
|
|
57
|
+
STOP = PLAIN | set("""
|
|
58
|
+
able across after also been before being between can could did does doing each every experience
|
|
59
|
+
experienced including into just like more most much need needs over role roles some such than
|
|
60
|
+
them through under using very well will within without work worked working would years year
|
|
61
|
+
have with that this from your their about must should strong good great team teams including
|
|
62
|
+
ability skills skill knowledge new help helps support supports ensure make makes
|
|
63
|
+
""".split())
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def read(path):
|
|
67
|
+
try:
|
|
68
|
+
with open(path, encoding="utf-8", errors="replace") as f:
|
|
69
|
+
return f.read()
|
|
70
|
+
except OSError as e:
|
|
71
|
+
print("claim_check: cannot read %s: %s" % (path, e.strerror), file=sys.stderr)
|
|
72
|
+
sys.exit(2)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def clean(line):
|
|
76
|
+
"""A line with its markup removed, so `**Go**` and `Go` read the same. Resumes kept as
|
|
77
|
+
Typst or LaTeX source escape `$`, `&`, `%` and `#`; the escapes are dropped too."""
|
|
78
|
+
line = LINK.sub(r"\1", line)
|
|
79
|
+
line = re.sub(r"\\([$&%#_])", r"\1", line)
|
|
80
|
+
line = re.sub(r"(?<![$£€\w.,])\d+(?:\.\d+)?(?:em|mm|pt|cm|px|fr)\b", " ", line) # layout lengths
|
|
81
|
+
line = line.replace("’", "'").replace("‘", "'").replace("–", " - ").replace("—", " - ")
|
|
82
|
+
return re.sub(r"[*_`~]", "", line)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def numbers(text):
|
|
86
|
+
"""{(value, is_percent)} for every figure in the text. "$2M" and "2 million" are one value."""
|
|
87
|
+
found = set()
|
|
88
|
+
for m in NUMBER.finditer(text):
|
|
89
|
+
try:
|
|
90
|
+
value = float(m.group(1).replace(",", ""))
|
|
91
|
+
except ValueError:
|
|
92
|
+
continue
|
|
93
|
+
unit = (m.group(2) or m.group(3) or "").lower()
|
|
94
|
+
found.add((value * MULT.get(unit, 1), bool(m.group(4))))
|
|
95
|
+
return found
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def stem(word):
|
|
99
|
+
w = word.lower().strip("'.")
|
|
100
|
+
if w.endswith("'s"):
|
|
101
|
+
w = w[:-2]
|
|
102
|
+
for s in SUFFIXES:
|
|
103
|
+
if w.endswith(s) and len(w) - len(s) >= 4:
|
|
104
|
+
return w[: -len(s)]
|
|
105
|
+
return w
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def key(word):
|
|
109
|
+
"""How a name is compared: case, dots, a plural, a possessive or a contraction don't matter."""
|
|
110
|
+
w = word.lower().strip("'")
|
|
111
|
+
w = re.sub(r"'(?:s|m|d|ve|ll|re|t)$", "", w)
|
|
112
|
+
w = w.replace(".", "") or w
|
|
113
|
+
return w[:-1] if len(w) > 4 and w.endswith("s") and not w.endswith("ss") else w
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def vocabulary(text):
|
|
117
|
+
names, stems = set(), set()
|
|
118
|
+
for line in text.splitlines():
|
|
119
|
+
for w in WORD.findall(clean(line)):
|
|
120
|
+
names.add(key(w))
|
|
121
|
+
stems.add(stem(w))
|
|
122
|
+
flat = " ".join(key(w) for line in text.splitlines() for w in WORD.findall(clean(line)))
|
|
123
|
+
return names, stems, " " + flat + " "
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def looks_named(word):
|
|
127
|
+
"""True for a word that is a name whatever its position: AWS, JavaScript, C++, k8s, .NET."""
|
|
128
|
+
body = word.lstrip(".")
|
|
129
|
+
return bool(re.search(r"[A-Z]", body[1:]) or re.search(r"[0-9+#]", body) or word.startswith("."))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def phrases(line):
|
|
133
|
+
"""Runs of capitalised or name-shaped words in one line, as lists of words.
|
|
134
|
+
|
|
135
|
+
The first word of a line or sentence is capitalised by grammar, not because it is a name,
|
|
136
|
+
so it only counts when it is name-shaped itself or opens a longer capitalised run."""
|
|
137
|
+
text = LIST_MARK.sub("", clean(line))
|
|
138
|
+
out, run, start_of_sentence = [], [], True
|
|
139
|
+
tokens = re.findall(r"(?<![A-Za-z0-9])\.?[A-Za-z][A-Za-z0-9+#']*(?:\.[A-Za-z0-9]+)*|&|[.!?;:]\s|[,|·/()]|\s-\s", text + " ")
|
|
140
|
+
for i, tok in enumerate(tokens):
|
|
141
|
+
if not (tok[0].isalpha() or tok[0] in ".&") or tok.strip() in (".", "!", "?", ";", ":"):
|
|
142
|
+
if run:
|
|
143
|
+
out.append(run)
|
|
144
|
+
run = []
|
|
145
|
+
start_of_sentence = tok.strip() in (".", "!", "?")
|
|
146
|
+
continue
|
|
147
|
+
if "'" in tok and key(tok) in PLAIN: # I'm, I've, we'd
|
|
148
|
+
tok = key(tok)
|
|
149
|
+
capital = tok[0].isupper() or looks_named(tok)
|
|
150
|
+
if capital and not (start_of_sentence and not looks_named(tok) and tok.lower() in PLAIN):
|
|
151
|
+
run.append((tok, start_of_sentence))
|
|
152
|
+
elif run and tok.lower() in JOINERS and i + 1 < len(tokens) and tokens[i + 1][:1].isupper():
|
|
153
|
+
run.append((tok, False))
|
|
154
|
+
else:
|
|
155
|
+
if run:
|
|
156
|
+
out.append(run)
|
|
157
|
+
run = []
|
|
158
|
+
start_of_sentence = False
|
|
159
|
+
if run:
|
|
160
|
+
out.append(run)
|
|
161
|
+
cleaned = []
|
|
162
|
+
for r in out:
|
|
163
|
+
# A lone sentence-opening word ("Led", "Built") is grammar, not a name.
|
|
164
|
+
if len(r) == 1 and r[0][1] and not looks_named(r[0][0]):
|
|
165
|
+
continue
|
|
166
|
+
# A sentence-opening verb in front of a name ("Led AWS migration") is dropped from the run.
|
|
167
|
+
if len(r) > 1 and r[0][1] and not looks_named(r[0][0]) and r[0][0].lower() not in PLAIN:
|
|
168
|
+
r = r[1:] if r[0][0].lower().endswith(("ed", "ing")) else r
|
|
169
|
+
words = [w for w, _ in r]
|
|
170
|
+
while words and words[-1].lower() in JOINERS:
|
|
171
|
+
words.pop()
|
|
172
|
+
if words:
|
|
173
|
+
cleaned.append(words)
|
|
174
|
+
return cleaned
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def check(draft, sources, posting):
|
|
178
|
+
src_names, src_stems, src_flat = vocabulary("\n".join(sources))
|
|
179
|
+
src_numbers = numbers("\n".join(clean(s) for s in sources))
|
|
180
|
+
post_names, post_stems, _ = vocabulary(posting or "")
|
|
181
|
+
post_numbers = numbers(clean(posting or ""))
|
|
182
|
+
findings, seen = [], set()
|
|
183
|
+
|
|
184
|
+
def add(kind, what, n, line, in_posting=False):
|
|
185
|
+
if (kind, what.lower()) in seen:
|
|
186
|
+
return
|
|
187
|
+
seen.add((kind, what.lower()))
|
|
188
|
+
findings.append({"kind": kind, "text": what, "line": n, "context": line.strip()[:160],
|
|
189
|
+
"in_posting": in_posting})
|
|
190
|
+
|
|
191
|
+
for n, raw in enumerate(draft.splitlines(), 1):
|
|
192
|
+
line = clean(raw)
|
|
193
|
+
if not line.strip() or DATE_LINE.match(LIST_MARK.sub("", line)):
|
|
194
|
+
continue # a letter's own date line claims nothing
|
|
195
|
+
body = LIST_MARK.sub("", line)
|
|
196
|
+
for m in NUMBER.finditer(body):
|
|
197
|
+
got = next(iter(numbers(m.group(0))), None)
|
|
198
|
+
if got and got not in src_numbers:
|
|
199
|
+
add("number", m.group(0).strip(), n, raw, got in post_numbers)
|
|
200
|
+
for words in phrases(raw):
|
|
201
|
+
content = [w for w in words if w.lower() not in JOINERS]
|
|
202
|
+
missing = [w for w in content if key(w) not in src_names and w.lower() not in PLAIN]
|
|
203
|
+
if missing:
|
|
204
|
+
add("name", " ".join(words), n, raw, all(key(w) in post_names for w in missing))
|
|
205
|
+
elif len(content) > 1 and all(w.lower() not in PLAIN for w in content):
|
|
206
|
+
flat = " ".join(key(w) for w in words if w != "&")
|
|
207
|
+
if " " + flat + " " not in src_flat:
|
|
208
|
+
add("combination", " ".join(words), n, raw)
|
|
209
|
+
if posting:
|
|
210
|
+
for w in WORD.findall(body):
|
|
211
|
+
s = stem(w)
|
|
212
|
+
if (len(s) >= 4 and w.lower() not in STOP and s in post_stems and s not in src_stems
|
|
213
|
+
and key(w) not in src_names and not w[0].isupper() and not looks_named(w)):
|
|
214
|
+
add("borrowed", w.lower(), n, raw, True)
|
|
215
|
+
return findings
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def main():
|
|
219
|
+
ap = argparse.ArgumentParser(description="List what a draft says that the candidate's own material doesn't.")
|
|
220
|
+
ap.add_argument("draft")
|
|
221
|
+
ap.add_argument("--source", action="append", required=True, metavar="FILE",
|
|
222
|
+
help="the candidate's own resume or notes; repeat for more than one")
|
|
223
|
+
ap.add_argument("--posting", metavar="FILE", help="the job posting")
|
|
224
|
+
ap.add_argument("--json", action="store_true")
|
|
225
|
+
a = ap.parse_args()
|
|
226
|
+
|
|
227
|
+
findings = check(read(a.draft), [read(p) for p in a.source], read(a.posting) if a.posting else None)
|
|
228
|
+
if a.json:
|
|
229
|
+
print(json.dumps({"draft": a.draft, "findings": findings}, indent=1))
|
|
230
|
+
return 1 if findings else 0
|
|
231
|
+
if not findings:
|
|
232
|
+
print("PASS %s: every figure and name is in the source material." % a.draft)
|
|
233
|
+
return 0
|
|
234
|
+
labels = {"number": "Figures not in the source", "name": "Names not in the source",
|
|
235
|
+
"combination": "Words the source has, but not together",
|
|
236
|
+
"borrowed": "Wording taken from the posting"}
|
|
237
|
+
print("REVIEW %s: %d item(s) to check against the source material." % (a.draft, len(findings)))
|
|
238
|
+
for kind in ("number", "name", "combination", "borrowed"):
|
|
239
|
+
rows = [f for f in findings if f["kind"] == kind]
|
|
240
|
+
if not rows:
|
|
241
|
+
continue
|
|
242
|
+
print("\n%s (%d)" % (labels[kind], len(rows)))
|
|
243
|
+
for f in rows:
|
|
244
|
+
note = " [in posting]" if f["in_posting"] and kind != "borrowed" else ""
|
|
245
|
+
print(" line %d: %s%s\n %s" % (f["line"], f["text"], note, f["context"]))
|
|
246
|
+
return 1
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
if __name__ == "__main__":
|
|
250
|
+
sys.exit(main())
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: job-fit-analysis
|
|
3
|
+
description: Compare a job posting with a resume and say honestly whether to apply: each requirement marked met, partly met, not shown or not met, with the resume line it rests on; the requirements an employer screens on listed first; and the questions whose answers would change the picture. Works for any occupation and level. Use when the user asks "am I a good fit for this job", "should I apply for this", "how does my resume match this posting", or wants the gaps between a job description and their CV before applying.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# job-fit-analysis
|
|
7
|
+
|
|
8
|
+
You compare one job posting with one person's resume and tell them where they stand before
|
|
9
|
+
they spend an evening on the application. The reader is the candidate. They need a straight
|
|
10
|
+
answer, the evidence behind it, and to know which gaps are real and which are only missing
|
|
11
|
+
from the page. It works the same for a nurse, a warehouse supervisor, a graduate or a staff
|
|
12
|
+
engineer: the posting sets the requirements, the resume is the evidence.
|
|
13
|
+
|
|
14
|
+
## How to respond
|
|
15
|
+
|
|
16
|
+
These four rules outrank the steps below.
|
|
17
|
+
|
|
18
|
+
- **Answer first.** The first sentence answers what they asked: apply or don't, and why.
|
|
19
|
+
The whole analysis is in the reply. Do not put it in a file unless they ask for one.
|
|
20
|
+
- **Use only what you were given.** The resume and what the person told you are the only
|
|
21
|
+
evidence. Nothing is credited because people in that job usually have it.
|
|
22
|
+
- **Deliver from what you have.** With a posting and three lines about the person, compare
|
|
23
|
+
those. Do not stop to ask for a full resume.
|
|
24
|
+
- **Write to the candidate.** Address them as "you", never by name or as "he", "she" or
|
|
25
|
+
"the candidate". Plain words, no scoring jargon, no mention of this skill. When they gave
|
|
26
|
+
you a few lines and no resume, say "what you told me", never "your resume".
|
|
27
|
+
|
|
28
|
+
1. **Read everything the person gave you.** The resume is the main evidence, and so is
|
|
29
|
+
any other file of theirs they point to or that sits beside it: a LinkedIn summary, a
|
|
30
|
+
portfolio page, a project's README. Evidence from one of those counts in full: mark the
|
|
31
|
+
requirement `Met` or `Partly` on the strength of it, say where it came from, and say it
|
|
32
|
+
is not on the resume yet, because the employer will only see the resume.
|
|
33
|
+
|
|
34
|
+
When the posting is a link, read the full text. If you cannot open it, say so in one line
|
|
35
|
+
and ask for the text pasted in. Give no verdict and list no requirements for a posting you
|
|
36
|
+
have not read, and never rebuild one from what you remember of the employer. Do not guess
|
|
37
|
+
at why the link would not open.
|
|
38
|
+
|
|
39
|
+
2. **List the posting's requirements.** Keep the employer's own wording. Sort
|
|
40
|
+
them into what the posting calls required and what it calls preferred. When the posting
|
|
41
|
+
doesn't say, treat what it lists first or repeats as required, and say you inferred it.
|
|
42
|
+
|
|
43
|
+
3. **Find what could get the application rejected.** Two kinds of requirement do it: the
|
|
44
|
+
ones a recruiter or an application form checks before anyone reads the rest (a licence or
|
|
45
|
+
registration, a degree, a certification, a minimum number of years, the right to work,
|
|
46
|
+
location or shift, a clearance, a language), and any other required item the resume does
|
|
47
|
+
not meet, such as a named system the posting lists under "must have". These go first,
|
|
48
|
+
because one of them outweighs five met skills.
|
|
49
|
+
|
|
50
|
+
4. **Mark each requirement against the evidence** with one of four words:
|
|
51
|
+
- **Met**: the resume shows it. Quote the line.
|
|
52
|
+
- **Partly**: the resume shows something close, smaller or older. Say what it shows and
|
|
53
|
+
what is short: "team of 12; the posting asks for 20 or more".
|
|
54
|
+
- **Not shown**: the resume is silent. The person may well have it.
|
|
55
|
+
- **Not met**: the resume shows otherwise, such as a diploma where a degree is required
|
|
56
|
+
or two years where five are asked for.
|
|
57
|
+
|
|
58
|
+
A similar tool is not the named tool. Cerner is not Epic, an in-house warehouse system is
|
|
59
|
+
not SAP: when the posting requires the named one, mark it `Not met` and give the similar
|
|
60
|
+
one as the nearest thing you have. A related task is not the named skill: cashing up a
|
|
61
|
+
till is not bookkeeping in Xero, so that is `Not shown`.
|
|
62
|
+
|
|
63
|
+
Take lengths of time only from dates the resume gives for that exact thing. When the
|
|
64
|
+
posting asks for two years of something and the resume shows the activity with no start
|
|
65
|
+
date, mark it `Partly`, say the resume doesn't show how long, and ask. Never state a
|
|
66
|
+
duration you worked out from a neighbouring date.
|
|
67
|
+
|
|
68
|
+
5. **Give a verdict the person can act on.** Open with a plain sentence that says whether
|
|
69
|
+
to apply, in the terms they asked ("Yes, apply", "Apply, but expect the degree to be a
|
|
70
|
+
problem", "Probably not worth your weekend unless..."), then one of four labels and the
|
|
71
|
+
reason:
|
|
72
|
+
- **Strong match**: every required item is met, or partly met with close evidence.
|
|
73
|
+
- **Worth applying**: nothing that would get it rejected is unmet, and most of the rest
|
|
74
|
+
is met.
|
|
75
|
+
- **Long shot**: something that could get it rejected is unmet. Say what would have to be
|
|
76
|
+
true for it to be worth the time, and whether you would still send it.
|
|
77
|
+
- **Not a match**: a requirement that cannot be worked around is unmet, such as a licence.
|
|
78
|
+
|
|
79
|
+
Write the table first and take the count from it. The opening sentence counts every
|
|
80
|
+
required item that is `Not met` or `Partly`, not only the worst one: "four of the six required items aren't met: the degree, the team size,
|
|
81
|
+
advanced Excel and SAP". It must agree with the table below it. Give the verdict on what
|
|
82
|
+
you know now; say what answer would raise it, but do not make the verdict wait on the
|
|
83
|
+
answer. Do not soften a long shot into encouragement, do not harden a workable gap into a
|
|
84
|
+
refusal, and do not give a percentage.
|
|
85
|
+
|
|
86
|
+
6. **Say what to bring forward.** List the two to four things already in the resume that
|
|
87
|
+
answer the posting best and are buried, understated or worded differently from the
|
|
88
|
+
posting. Give the resume's wording and the posting's wording side by side.
|
|
89
|
+
|
|
90
|
+
7. **Close with what to do next**, in two to four lines: what to lead the application with,
|
|
91
|
+
what to say about the main gap, and the one or two questions whose answers would change
|
|
92
|
+
the verdict ("Have you used Epic anywhere? If so, where and for how long?"). When a
|
|
93
|
+
required item is not shown, ask once whether anything outside the resume covers it: a
|
|
94
|
+
side project, a repository, a portfolio, a volunteer role. People leave their best
|
|
95
|
+
evidence off the page. Anything you credited from another file goes here too, as a line
|
|
96
|
+
to add to the resume. Never tell
|
|
97
|
+
them to add a keyword they have not said is true, and do not end on a list of questions
|
|
98
|
+
with no advice.
|
|
99
|
+
|
|
100
|
+
8. **Lay the reply out in this order:** the answer and verdict; what could get it rejected;
|
|
101
|
+
one table covering every requirement (requirement, required or preferred, status,
|
|
102
|
+
evidence); what to bring forward; what to do next. Each requirement appears in the table
|
|
103
|
+
once and nothing is repeated in a second table or restated section by section.
|
|
104
|
+
|
|
105
|
+
Match the length to what you were given. A short posting and a few lines about the person
|
|
106
|
+
gets a short answer: the verdict, one line per requirement, and what to do, in under 250
|
|
107
|
+
words and with no table. A full resume against a long posting gets the table, and still
|
|
108
|
+
fits a page.
|
|
109
|
+
|
|
110
|
+
**With a posting and no resume**, compare against whatever the person said about themselves,
|
|
111
|
+
mark the rest `Not shown`, and say a resume would settle those. **With a resume and no
|
|
112
|
+
posting**, ask for the posting in one line: there is nothing to compare against.
|
|
113
|
+
|
|
114
|
+
## Quality bar
|
|
115
|
+
|
|
116
|
+
- **Every Met and Partly quotes the resume.** A status with no line behind it is a guess.
|
|
117
|
+
- **What could get the application rejected is named first**, never left as one row among many.
|
|
118
|
+
- **No length of time appears that the resume's own dates don't give.**
|
|
119
|
+
- **`Not shown` and `Not met` are kept apart.** One is a question, the other is a gap.
|
|
120
|
+
- **Nothing is credited that the resume or the person doesn't state.**
|
|
121
|
+
- **The verdict matches the table.** An unmet required degree cannot sit under "strong
|
|
122
|
+
match", and a verdict that names one gap cannot sit over a table that shows four.
|
|
123
|
+
|
|
124
|
+
## When to use this skill
|
|
125
|
+
|
|
126
|
+
- ✅ Deciding whether a posting is worth applying for
|
|
127
|
+
- ✅ Finding the gaps between a resume and a posting before tailoring the resume
|
|
128
|
+
- ✅ Checking several postings against one resume to choose where to spend effort
|
|
129
|
+
|
|
130
|
+
## When NOT to use this skill
|
|
131
|
+
|
|
132
|
+
- ❌ Rewriting the resume for the posting. Use `resume-tailor`.
|
|
133
|
+
- ❌ Writing the cover letter. Use `cover-letter`.
|
|
134
|
+
- ❌ Critiquing the resume as a document, with no job in mind. Use `doc-critique`.
|
|
135
|
+
|
|
136
|
+
## Anti-patterns to avoid
|
|
137
|
+
|
|
138
|
+
- ❌ **"87% match."** A percentage hides which requirement is the problem.
|
|
139
|
+
- ❌ **Cheerleading.** "You'd be a great fit!" over an unmet required degree wastes the
|
|
140
|
+
person's evening.
|
|
141
|
+
- ❌ **Crediting the usual.** "As a nurse you will have used Epic" is an invention.
|
|
142
|
+
- ❌ **Treating a similar tool as the named one.**
|
|
143
|
+
- ❌ **Advising them to add keywords** so the resume passes a filter. If it isn't true it
|
|
144
|
+
doesn't go in.
|
|
145
|
+
- ❌ **Judging the person.** No remarks on age, gaps, family, health or anything a recruiter
|
|
146
|
+
may not lawfully weigh.
|
|
147
|
+
- ❌ **Inventing the posting.** A link you could not open is not a posting you have read.
|
|
148
|
+
- ❌ **Answering in a file.** They asked a question; the answer belongs in the reply.
|
|
149
|
+
- ❌ **A verdict with no advice.** "Long shot" followed by questions leaves them where they
|
|
150
|
+
started.
|
|
151
|
+
- ❌ **Showing the machinery.** No status legend longer than a line, no account of how the
|
|
152
|
+
comparison was produced, no remark about what you could or couldn't save.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Am I a good fit for this job? Here's the posting and my resume",
|
|
4
|
+
"should_trigger": true
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"query": "Should I apply for this role or is it a stretch?",
|
|
8
|
+
"should_trigger": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "What's missing from my CV for this job description?",
|
|
12
|
+
"should_trigger": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"query": "Compare my resume against these three postings and tell me which to go for",
|
|
16
|
+
"should_trigger": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"query": "Tailor my resume to this job posting",
|
|
20
|
+
"should_trigger": false
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"query": "Write a cover letter for this role",
|
|
24
|
+
"should_trigger": false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"query": "Critique my resume, it's not for any particular job",
|
|
28
|
+
"should_trigger": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"query": "Compare these three applicant tracking systems for our HR team",
|
|
32
|
+
"should_trigger": false
|
|
33
|
+
}
|
|
34
|
+
]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "job-fit-analysis",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "My CV is in resume.md and the job I'm looking at is in posting.md. Am I a good fit? Be honest, I don't want to waste a weekend on it.",
|
|
7
|
+
"assertions": [
|
|
8
|
+
"The Epic requirement is marked as not met, partly met or not shown, and the reply says her CV shows Cerner, not Epic, naming both systems",
|
|
9
|
+
"Basic Life Support instructor certification is shown as not held: the CV has BLS provider only",
|
|
10
|
+
"The teaching requirement is credited from precepting newly qualified nurses (9 preceptees) or the 2022 mentorship module, and the reply notes or asks how long she has been precepting, because the CV does not show two years of it",
|
|
11
|
+
"NMC registration, a nursing degree and at least 3 years of post-registration medical-surgical experience are each marked as met",
|
|
12
|
+
"A master's degree and simulation lab experience are shown as not held or not shown, and as preferred items, not required ones",
|
|
13
|
+
"The reply opens with an overall verdict on whether to apply, before the requirement-by-requirement detail",
|
|
14
|
+
"It points to the sepsis screening guide or the Cerner superuser role as existing evidence worth bringing forward",
|
|
15
|
+
"It does not credit her with any tool, qualification or experience that is not in the CV, and does not advise adding one"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": 2,
|
|
20
|
+
"prompt": "Thinking of applying for this (posting.md). My resume's in resume.md. What are my chances and what's missing?",
|
|
21
|
+
"assertions": [
|
|
22
|
+
"The bachelor's degree is marked as required and not met: the resume shows a high school diploma and 18 uncompleted college credits",
|
|
23
|
+
"The degree gap is stated in the verdict or before the detailed list, as something likely to screen him out, not only as one row among many",
|
|
24
|
+
"The team-size requirement is marked short, with both numbers: he supervises 12 and the posting asks for 20 or more",
|
|
25
|
+
"SAP Extended Warehouse Management is marked not shown or partly met, and the reply says the resume shows an in-house warehouse system instead",
|
|
26
|
+
"Advanced Excel is not marked fully met: the resume shows rosters and attendance in Excel, and pivot tables and VLOOKUP are not shown",
|
|
27
|
+
"The safety record (zero lost-time incidents for 14 months) and the forklift certification are marked as met, quoting the resume",
|
|
28
|
+
"The overall verdict is not a strong match, and matches the unmet degree requirement",
|
|
29
|
+
"It does not advise him to claim a degree, SAP experience, a bigger team or any keyword he has not shown"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": 3,
|
|
34
|
+
"prompt": "Is this worth applying for? I've been a barista for 4 years, shift lead for the last 2 - I do the rota for 9 people, the weekly stock order and cashing up. No degree.\n\nOffice Manager, Pell & Dray Architects (14 staff)\n- 2+ years in an office administration role\n- Managing supplier relationships and ordering\n- Organising staff schedules and meeting rooms\n- Bookkeeping experience with Xero\n- Confident with Microsoft 365\n- Friendly first point of contact for clients and visitors",
|
|
35
|
+
"assertions": [
|
|
36
|
+
"It delivers a requirement-by-requirement comparison from what was given, and does not stop to ask for a resume first",
|
|
37
|
+
"The 2+ years of office administration is marked not met or named as the main gap, since the experience is in a cafe and not an office",
|
|
38
|
+
"The rota for 9 people is credited against organising staff schedules, and the weekly stock order against ordering, each citing what the person said",
|
|
39
|
+
"Xero is marked not shown or not met, and cashing up is not presented as Xero or bookkeeping-software experience",
|
|
40
|
+
"Microsoft 365 is marked not shown or asked about, not assumed",
|
|
41
|
+
"The lack of a degree is not treated as a gap, because the posting does not ask for one",
|
|
42
|
+
"It gives an overall verdict that is honest about the office-experience gap",
|
|
43
|
+
"It does not invent an employer name, a qualification, a tool or any experience the person did not state"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": 4,
|
|
48
|
+
"held_out": "2026-10-05",
|
|
49
|
+
"prompt": "Would I get anywhere with this? CV is resume.md, job is posting.md.",
|
|
50
|
+
"assertions": [
|
|
51
|
+
"The qualification requirement is marked not met: she has AAT Level 3 and two of five Level 4 units, not Level 4 complete or part-qualified ACCA or CIMA",
|
|
52
|
+
"The 2 years in a management accounts or analyst role is marked not met or short: her roles are accounts payable clerk and finance administrator",
|
|
53
|
+
"Power BI is shown as not held, and the Excel workbook is not presented as Power BI experience",
|
|
54
|
+
"Advanced Excel is credited from the workbook with pivot tables and lookups, quoting the CV",
|
|
55
|
+
"Variance analysis and budget commentary are marked not shown or not met",
|
|
56
|
+
"Sage 200 and the accruals for goods received not invoiced are credited as relevant evidence",
|
|
57
|
+
"The reply opens with a clear answer on whether to apply",
|
|
58
|
+
"It does not credit her with any qualification, tool or experience that is not in the CV"
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": 5,
|
|
63
|
+
"held_out": "2026-10-05",
|
|
64
|
+
"prompt": "Head chef job at a hotel, posting.md. My CV's resume.md. Realistic or not?",
|
|
65
|
+
"assertions": [
|
|
66
|
+
"Level 3 Food Safety is marked not met: he holds Level 2, and his Level 3 is in Professional Cookery, which is a different qualification",
|
|
67
|
+
"Team size is marked short with both numbers: a brigade of 6 against 12 or more",
|
|
68
|
+
"Running the kitchen on the head chef's two days off is credited toward the sous-chef-with-full-responsibility requirement, quoting the CV",
|
|
69
|
+
"Costing is credited from the weekly specials, and the 70% gross profit target is noted as not shown",
|
|
70
|
+
"Banqueting is credited from covering weddings at Harbour Rooms Hotel, and hotel experience is marked met",
|
|
71
|
+
"The reply gives a clear answer on whether it is realistic",
|
|
72
|
+
"It does not credit him with a qualification, a cover count, a team size or a system that is not in the CV"
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": 6,
|
|
77
|
+
"prompt": "Am I a fit for this? CV is resume.md, job is posting.md. My LinkedIn about text is in linkedin-about.txt too.",
|
|
78
|
+
"assertions": [
|
|
79
|
+
"The onboarding or training requirement is credited from the monthly onboarding webinar described in the LinkedIn text",
|
|
80
|
+
"The reply says that evidence is not on the CV and should be added to it",
|
|
81
|
+
"Owning renewals is marked partly or not met: she supported renewals alongside the account managers and did not own them",
|
|
82
|
+
"The 3+ years in customer success or account management is marked not met or partly: her roles are in support",
|
|
83
|
+
"Gainsight is marked not shown or not met, and Salesforce is credited from the CV",
|
|
84
|
+
"Leading a small team is marked met from leading 6 support agents",
|
|
85
|
+
"Working with a product team on feedback is credited from the Customer Advisory Board or the ticket-trends report",
|
|
86
|
+
"The reply opens with a clear answer on whether to apply"
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": 7,
|
|
91
|
+
"prompt": "Would I be a fit for this one? https://careers.brightloop.example/jobs/4471 - my CV is resume.md",
|
|
92
|
+
"assertions": [
|
|
93
|
+
"The reply says it could not open or read the link",
|
|
94
|
+
"It asks for the posting's text to be pasted in or saved as a file",
|
|
95
|
+
"It does not list the job's requirements or mark any as met or not met, as though it had read the posting",
|
|
96
|
+
"It gives no verdict on fit",
|
|
97
|
+
"It does not state what Brightloop does or what the role involves",
|
|
98
|
+
"The reply is short, about 120 words or fewer"
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Clinical Nurse Educator — Surgical Division
|
|
2
|
+
|
|
3
|
+
**Northfield General Hospital** · Full time, permanent · Band 6
|
|
4
|
+
|
|
5
|
+
Northfield General is a 320-bed teaching hospital. The Surgical Division's education team supports 240 nursing staff across five wards.
|
|
6
|
+
|
|
7
|
+
## The role
|
|
8
|
+
|
|
9
|
+
You will plan and deliver clinical education for surgical nursing staff: induction for new starters, annual skills updates, and ward-based teaching after incidents and audits.
|
|
10
|
+
|
|
11
|
+
## You must have
|
|
12
|
+
|
|
13
|
+
- Current NMC registration (adult)
|
|
14
|
+
- A nursing degree
|
|
15
|
+
- At least 2 years' experience teaching, precepting or mentoring clinical staff
|
|
16
|
+
- At least 3 years' post-registration experience in an acute surgical or medical-surgical setting
|
|
17
|
+
- Experience using Epic, including supporting colleagues with it
|
|
18
|
+
|
|
19
|
+
## It would help if you have
|
|
20
|
+
|
|
21
|
+
- A master's degree in nursing or education, or to be working towards one
|
|
22
|
+
- Basic Life Support instructor certification
|
|
23
|
+
- Experience running sessions in a simulation lab
|
|
24
|
+
- Experience writing teaching materials or guidelines
|
|
25
|
+
|
|
26
|
+
## How to apply
|
|
27
|
+
|
|
28
|
+
Send a CV and a cover letter of no more than one page to the Surgical Education Lead. Closing date 24 October 2026.
|