Skip to content
Back to skills

Ops Recruiter

ASecurity

Turn a recruiter message plus Graham's approved resume/claim context into a drafted, humanized reply — webgpt writes, webkimi humanizes — with optional brave-search company research as a seed. Claim-bound (never mints facts) and human-transmitted only (never sends). Stores correspondence in Memory. Use when a recruiter emails or messages about a role and Graham wants a tailored reply drafted with comprehensive context. Composed by monitor-opportunities.

  • 7 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 23, 2026
ai-agentsgobashapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 8 files and shows the line behind each finding

Scanned September 23, 2026

npx -y skills add grahama1970/agent-skills --skill ops-recruiter --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ops Recruiter?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ops Recruiter
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/grahama1970-ops-recruiter/badge)](https://www.skillsdirectory.com/skills/grahama1970-ops-recruiter)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ops-recruiter
description: >
  Turn a recruiter message plus Graham's approved resume/claim context into a
  drafted, humanized reply — webgpt writes, webkimi humanizes — with optional
  brave-search company research as a seed. Claim-bound (never mints facts) and
  human-transmitted only (never sends). Stores correspondence in Memory. Use when
  a recruiter emails or messages about a role and Graham wants a tailored reply
  drafted with comprehensive context. Composed by monitor-opportunities.
triggers:
  - draft recruiter reply
  - respond to recruiter
  - recruiter response
  - reply to this recruiter message
  - ops-recruiter
provides:
  - recruiter-reply-draft
  - recruiter-correspondence-memory
---

# ops-recruiter

## Immutable goal

> Given a recruiter message, the target role, and Graham's approved resume/claim
> context, produce a clear, humanized, claim-bound reply DRAFT — never fabricating
> facts, never sending anything. The human always transmits.

This skill composes existing skills; it does not reimplement browser transport,
LLM routing, or mailbox access.

## Pipeline

```
recruiter message + role text + approved resume/claims
  recall      recruiter_correspondence memory -> prior thread + relationship flag
  research    $brave-search  -> company/role AND recruiter (LinkedIn page + history) seed (cited, degradable)
  build       context packet (incl. prior thread) + claim ledger + browser-prompt preflight
  gate        claim-bind check: every factual assertion maps to an approved claim
  draft       $ask webgpt    -> comprehensive first draft
  humanize    $ask webkimi   -> clarity + humanized-prose edit of that draft
  T0 gate     run.sh gate    -> deterministic token floor (fail-closed)
  T1 review   PROJECT AGENT  -> semantic claim-bind verdict vs ledger
                on FAIL: structured findings -> webgpt redraft -> webkimi -> T0 -> T1
                (<=3 rounds, each carrying a specific correction; else fail closed to human)
  store        $memory /store -> recruiter_correspondence collection
  return       DRAFT to the human. No send. Ever.
```

`run.sh` owns steps `build`, `gate`, and `store`. The `draft`/`humanize` steps
are `$ask` (webgpt then webkimi); `run.sh build` emits the exact preflighted
`$ask` commands so the composition boundary stays in `$ask`.

## Load-bearing contract (this is the skill, not the two model calls)

- **Claim-bound, never fact-minting — two-tier, independently reviewed.** The
  fact ledger is the approved `career_profile` claim snapshot or `RESUME.md`.
  webgpt/webkimi may reword, order, tighten, and choose emphasis; they may not
  invent employers, titles, dates, metrics, clearances, or a capability claim the
  ledger does not back. Two gates, in order:
  - **T0 deterministic (`run.sh gate`)** — numeric/fact-token floor; fails closed
    on any metric/date absent from the ledger. Cheap, automated, in the e2e.
  - **T1 semantic claim-bind — the PROJECT AGENT is the reviewer of record.** The
    creator (webgpt) and humanizer (webkimi) never certify their own draft. The
    project agent reads the produced draft against the ledger and issues a
    per-claim verdict (each factual sentence traces to a claim, or the draft is
    rejected), fail-closed, before the draft is handed to the human to send. This
    is the same boundary as everywhere else: a model seat's PASS is only
    evidence; the project agent verifies against local evidence before acceptance.
  A self-certifying model seat is not a substitute for the project-agent review.
- **Bounded course-correction loop on T1 FAIL.** If the project-agent review
  rejects a claim as unsupported, it does not stop and it does not blindly
  retry. It emits a structured finding (offending sentence, the unsupported
  claim, and what the ledger actually supports) and feeds that exact correction
  back to webgpt (redraft) -> webkimi (rehumanize) -> T0 -> T1 again. A retry
  that does not carry a specific correction is spray-and-pray and is forbidden.
  Cap at 3 rounds; on exhaustion, fail closed and hand the draft plus surviving
  findings to the human. Never send, never loop unbounded.
- **Relationship-aware, never re-introduces.** `build` recalls prior
  `recruiter_correspondence` for the recruiter/thread and sets a relationship
  flag (`existing`/`new`/`unknown`). An existing thread must not be written as
  first contact; if recall is unavailable the opening stays relationship-neutral
  rather than falsely claiming first contact.
- **Human-transmitted only.** Draft-and-return. No email send, no LinkedIn
  action. Mirrors monitor-opportunities `who transmits = the human`.
- **`$brave-search` is a seed, not authority.** Covers both company/role context
  and recruiter deep-research (their LinkedIn page and background/history) so the
  reply is informed by who is actually reaching out. Cited, and honestly
  degradable to "no research" without failing the draft.

## Correspondence memory

ALL correspondence with a recruiter or hiring contact — every channel, no
exceptions — persists in the single `recruiter_correspondence` Memory collection
via `$memory` `/store` (never raw AQL, never inline vector arrays). `source` is an
OPEN vocabulary: known values below, but the store never rejects a new channel,
so email, LinkedIn, call/interview transcripts, SMS, referral intros, ATS
messages, and manual notes all land on the same thread. One document per
message with deterministic `_key` (`<source>:<thread-id>:<message-id>`), fields:
`direction` (`inbound`/`draft`/`sent`/`meeting`), `source`
(`gmail`/`linkedin`/`manual`/`google-meet`/`live-evidence`), `recruiter`,
`company`, `role`, `body`, `role_ref`, `claim_keys[]`, `draft_ref`,
`received_at`, `tags`, `schema` (`ops_recruiter.correspondence.v1`). Optional
(webgpt-reviewed, graph-enabling): `reply_to_message_id` (exact predecessor —
enables causal `message_replies_to` edges; never inferred from timestamps),
`occurred_at` (canonical event time for draft/sent/meeting), `recruiting_company`
+ `employer_company` (normalized; preferred over parsing `company`). Optional but
VALIDATED `signals` block with closed enums (fail-closed): `disposition`
(`PURSUE|DEFER|DECLINE_LOW_RATE|DECLINE_PUSHY|DECLINE_OFF_MANDATE|NEEDS_HUMAN`),
`rate` (`ABOVE_FLOOR|AT_FLOOR|BELOW_FLOOR|RATE_UNKNOWN`), `tone`
(`NORMAL|PERSISTENT|PUSHY|UNKNOWN`) — so recall can filter
`/list {"filters":{"signals.disposition":"PURSUE"}}` and mine threads without
parsing prose. A call/interview transcript is stored as
`direction=meeting` on the same thread. Thread continuity fetches this thread
exactly via Memory `/list` filters; cross-thread semantic `$memory recall`
lights up once the memory repo registers `recruiter_correspondence` in
`builtin_sources()` (memory-repo change; ops-recruiter must not wire views or AQL).

## Ingestion boundaries (read before wiring any source)

- **Email → `/gmail`, NOT `$ops-google`.** `$ops-google` is the Gemini API
  budget skill and has nothing to do with mailbox access. Graham's
  `graham@grahama.co` inbox is reached only through the `/gmail` capability (the
  same one `mailbox-mining` delegates to). ops-recruiter consumes gmail messages
  that `/gmail` has already fetched; it does not talk to Gmail directly.
- **Meeting/call transcripts → `$ops-google-meet` / `$live-evidence`.**
  ops-recruiter does not record or transcribe. It consumes transcripts those
  skills already produced (Google Meet prep/companion and the live interview
  copilot) and stores them on the recruiter thread as `direction=meeting`,
  `source=google-meet` or `live-evidence`, so a call becomes part of the same
  thread history and future context.
- **LinkedIn research is delegated to `$ops-linkedin`.** ops-recruiter does not
  drive LinkedIn itself. `$ops-linkedin` (lead-gen lane) owns the authorized
  read-only recruiter/company-page research — a `$surf` headed tab in Graham's
  own session, human-supervised, after `--accept-account-risk`. Engagement
  (connecting, messaging/InMail, posting, commenting, background automation,
  bulk scraping) stays forbidden there. Login-free recruiter/company research
  still prefers `$brave-search`. ops-recruiter consumes the captured evidence
  into `recruiter_correspondence`.

## Commands

```bash
./run.sh status --json
./run.sh build --recruiter-message MSG.md --role ROLE.md --resume RESUME.md \
  [--recruiter R --thread-id T] [--research] [--out DIR]  # recalls prior thread; packet + $ask commands
./run.sh gate --draft DRAFT.md --claims CLAIMS.json # fail-closed claim-bind check
./run.sh store --message MSG.json                   # write one correspondence doc to Memory
./sanity.sh
```

## Compliance

- `$best-practices-skills`: this frontmatter, progressive disclosure (pipeline
  detail in `references/pipeline.md`), `sanity.sh`, retained `$agentic-evals`
  fixture asserting the claim-bind gate rejects an unbacked assertion.
- `$best-practices-readme`: README voice, with an explicit non-claims section:
  ops-recruiter does not send email, does not touch LinkedIn, and does not mint facts.

## Related skills

- `$ask` (webgpt draft, webkimi humanize) — composition transport.
- `$memory` — recruiter_correspondence collection.
- `$brave-search` — optional research seed.
- `/gmail` — email ingestion. `$ops-linkedin` — read-only LinkedIn evidence.
- `$monitor-opportunities` — composes this skill into the morning report.

## References

- `references/pipeline.md` — packet format, claim ledger, and the exact ask chain.

Files in this skill

  • SKILL.md9.4 KB
  • fixtures/agentic_eval.json5.8 KB
  • references/pipeline.md2.8 KB
  • run.sh341 B
  • sanity.sh1.9 KB
  • scripts/e2e_recruiter.sh4.1 KB
  • scripts/e2e_response_live.sh3.8 KB
  • scripts/recruiter.py13 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…