A personal AI workflow / An engineering case study

I automated
the busywork.
Not the decision.

My job-search workflow finds relevant roles, prepares evidence-based applications, and tracks replies. ChatGPT handles the reasoning. Software remembers the work. I choose what to send.

PERSONAL JOB SEARCH / CONTROL ROOM
Multiple sources. One workflow.
AshbyGreenhouseLever+5 adapters
01 / FINDDiscover
02 / JUDGEScore & filter
03 / BUILDPrepare
Evidence before prose
An application that still sounds like me.

Research → truthful CV → form-ready answers

CV.pdfAnswersLetter, when supported
THE FINAL GATE / HUMANI review. I decide. I submit.
CONCEPTUAL VIEW · NO EMPLOYER ACTIONS FROM THIS PAGE
A real system, with inspectable evidence.Click any metric for its definition.

Worker figures: 12 September 2026, 09:38 UTC. Inventory and schedule configuration inspected the same day. These are different populations, not one application funnel. Evaluated ≠ tracked ≠ prepared ≠ submitted. 09

01 / The experience

From a vacancy
to ready for my review.

This is not a “spray and pray” application bot. It reduces repeated work while keeping the facts, the questions and the final decision visible. 01

FOLLOW A HYPOTHETICAL APPLICATION
DISCOVERY / SOURCE DATA

Find broadly, keep the full evidence.

AI Match ingests job boards into PostgreSQL. A deterministic GitHub Actions worker follows discovery searches, deduplicates identities, retrieves complete postings and packages them for ChatGPT. It keeps cursors and evidence so the next run can continue.

What this stage produces

A full-posting packet plus durable discovery state—not just a promising snippet.

050708
There is an off-ramp. A genuine missing answer pauses the affected work. Confirmed Spain-incompatible roles are quarantined before further preparation; scheduled runs cannot override that decision. 01
02 / System design

AI for judgment.
Code for the machinery.

The assistant coordinates a network of tools. GitHub keeps the durable queue, and deterministic workers do the repetitive transport, validation and rendering. 08

Skills = the playbooks

Versioned instructions for how to perform each specialist task.

MCP = the tool connection

A standard way for the host assistant to call external capabilities. 17

Durable state = the memory

Queues, immutable inputs, evidence and receipts outside a chat. 08

Discovery pathLogical responsibilities, not a live trace
Preparation & reporting connections
Two independent data views: the worker index measures discovery operations; the existing dashboard derives application outcomes from Project history. The radar reads AI Match directly.

The three task schedules coordinate separate responsibilities. The AI Match ingestion service also has its own three-hour schedule; Actions workers are event-driven, not extra hourly ChatGPT agents. 05 06 08

03 / The integrations

Three custom MCP connections.
Sixteen callable tools.

Discovery, document production and notifications are separate services with narrow responsibilities. GitHub, Gmail and read-only web inspection support the rest of the workflow.

2 tools

AI Match

The search layer. Compact rows make triage cheap; full descriptions preserve the actual requirements before a decision is made.

SearchPostgreSQL websearch, company and recency filters; up to 100 results per page.
DetailsUp to five complete postings per call. Search pagination keeps total, page and hasMore.
RuntimeNext.js MCP endpoint + Effect handlers. Ingestion uses Node, BullMQ/Redis and PostgreSQL.
Inspect the 2 tool names
  • search_job_postings
  • get_job_postings
05 07
11 tools

Job Search Assistant

The artifact layer. Retrieves the current canonical CV, validates small changes and evidence-backed prose, then requests the website’s PDF renderer.

Contract5 CV tools + 5 cover-letter tools + 1 narrative-answer validator.
BoundaryVercel coordinates. Sandoche-Website Actions renders. It does not rebuild the CV in another layout.
AccessOAuth for MCP; bearer-protected HTTP API. Shared service logic avoids API/MCP behavior drift.
Inspect the 11 tool names
  • get_current_cv
  • get_cv_tailoring_context
  • create_cv_customization
  • render_cv_pdf
  • get_cv_pdf_render
  • validate_narrative_answer
  • get_cover_letter_context
  • get_cover_letter_evidence
  • create_cover_letter
  • render_cover_letter_pdf
  • get_cover_letter_pdf_render
03 14
3 tools

Telegram Elara

The notification layer. Delivers readable, consolidated updates to one configured destination, with a separate tool for photos.

MessagesRich Markdown supports headings, lists and tables. Photo posts are separate, with plain-text captions.
BoundaryNo selectable destination or Telegram administration. The private endpoint is protected by a secret capability URL.
EvidenceA returned message receipt proves a send. The read-only connection check does not prove Telegram delivery.
Inspect the 3 tool names
  • get_telegram_relay_status
  • send_rich_markdown_to_telegram_channel
  • send_photo_to_telegram_channel
04
The clever bit is the separation.

Instructions decide what should happen. Tools perform bounded operations. Persisted receipts record what actually happened. None of these alone proves the whole workflow succeeded.

01 08
04 / The specialist library

Eleven skills.
One consistent process.

Reusable, versioned playbooks—not eleven independent agents. Each owns a specific piece of the work, and the orchestrator preserves the boundaries between them. 02

11 / 11 skills visible

Coordinationv4.1.0

The conductor

job-search-orchestrator

Separates discovery from preparation, selects the next work, persists checkpoints and owns consolidated reporting.

It prepares. It never submits.
01
Evidence & voicev1.0.0

Research once. Reuse everywhere.

company-research

Builds a first-party company dossier that can support a letter, a motivation answer and interview preparation.

At least two distinct first-party sources.
010203
Evidence & voicev1.0.0

My reasons, not invented reasons

candidate-motivation-profile

Retrieves confirmed motivations and separates them from inferred preferences or details needing recollection.

Missing motivation becomes a focused human question.
0203
Evidence & voicev1.1.0

Keep my voice

write-like-sandoche-not-like-ai

Applies document-specific writing adapters and Vale rules after the company facts and experience evidence exist.

Style cannot manufacture evidence.
0102
CV intelligencev1.2.1

Tailor the evidence

cv-tailoring

Makes concise, supported patches to the canonical CV, with truthful headlines, descriptions and allowed skill tags.

No fabricated experience or unsupported seniority.
0203
CV intelligencev1.2.0

Estimate the match

ashby-emulator

Provides a heuristic, ATS-like view used to compare CV candidates against the same target role.

Not an employer’s actual ATS score or a hiring prediction.
0212
CV intelligencev1.3.0

Improve. Compare. Stop.

ashby-cv-optimizer

Freezes the baseline, evaluates truthful revisions, tests summary visibility and retains the best supported plateau.

Trial evidence and a before/after audit are required.
0102
Application packv2.1.0

A reason to care

cover-letter

Connects first-party company research, confirmed motivation and relevant experience in a validated letter.

Only for a supported required, optional or general-info destination.
010203
Application packv2.3.0

Coordinate one application

job-application

Combines the specialist document workflows for a specific role while preserving evidence and writing standards.

Document creation is separate from employer submission.
010212
Application packv2.2.0

Fit the actual form

job-application-preparer

Inspects fields and uploads before generation, collects missing required answers and builds a validated answer sheet.

Inspection is read-only; unknown required facts stay questions.
0102
Human-controlledv2.0.0

The explicit action boundary

job-application-submitter

A separate skill for validated answers and action-time confirmation. It exists in the library, outside the scheduled path.

Never invoked by the discovery or preparation cron.
0102

Versions come from the repository manifest. The scheduled contract requires compatible installed skills, but this page is not an audit of every installed package. The submission skill is deliberately excluded from scheduled runs.

05 / Automation, without one giant cron

Three loops.
Different jobs to do.

Separating the loops prevents new discoveries from continually displacing unfinished applications. Each mode owns its own state and reporting duties. 08 15

:00EVERY HOUR

Discovery & scoring

Read complete packets, apply eligibility gates, judge relevance, deduplicate against history, and initialize a properly validated ticket for a selected role.

Atlantic/CanaryDiscovery leaseStrictly >70
Stops at the handoff. No company research, CV optimization or cover letters in this mode. One consolidated Telegram + ChatGPT summary per invocation. 01 15 18
:30EVERY HOUR

Application preparation

Resume existing tickets, including manual additions. Prioritize answered blockers and in-progress work, then older queued roles rather than only fresh high scores.

Atlantic/CanaryPreparation leaseFairness after 24h
Research, form inspection, documents and validated answers. Persist unfinished work for the next run. One consolidated Telegram + ChatGPT summary per invocation. 01 15
13hOVERLAPPING EMAIL WINDOW

Job Email Watch

Check hourly across normal mail and Spam, read or unread. Match each recruitment update to the correct existing issue and deduplicate by Gmail message ID.

Europe/ParisHourly condition watchSilent when unchanged
Append the email as evidence; add existing rejection/phase labels when warranted. Alert only for new relevant updates. Never guess an ambiguous issue match. 15
3h

AI Match’s separate ingestion clock

A Redis-backed scheduler fans out source-board sync jobs to eight provider adapters. This is service-side ingestion, not a fourth ChatGPT task. 05 06

Actions wakes on events

Discovery requests and decisions trigger worker processing; application validation is independent. PDF workflows are requested when a final render is authorized. 08 13 14

00 → 50 / SUBSTANTIVE WORK50 → 55 / CHECKPOINT & REPORT
Leave time to finish responsibly.

Discovery and preparation stop starting new work at minute 50 and reserve through minute 55 for checkpointing and notification. A cutoff is not a throughput guarantee. 15

06 / Quality is a sequence of gates

Make it personal.
Keep it provable.

The system does not turn a job description into invented experience. It starts with evidence, improves supported wording, then checks the actual delivered artifacts. 01 03

Four inputs stay separate.

01
Company research

What the company actually builds, based on first-party sources.

02
Confirmed motivation

Why I genuinely care—not a reason inferred from a project name.

03
Experience evidence

The current canonical CV and relevant project dossiers.

04
My writing voice

Applied after the factual connection exists, with the right document adapter.

Subjective narrative answers require target-relevant research references and a confirmed candidate reference. The wording must actually connect the two—not merely include citations. 03

The document production line

  1. Inspect before generating

    Read the actual form. Discover required fields, supported letter destinations, upload formats and genuine blockers.

  2. Compare against a frozen CV baseline

    Evaluate supported revisions, including the headline and summary visibility. Retain the best truthful plateau and a before/after audit.

  3. Validate the final text, not an earlier draft

    Apply voice and Vale. Narrative answers must pass. Exact-input validation receipts gate each new render request.

  4. Render through the canonical website

    Use the Astro/Puppeteer pipeline, established styling and layout. Cover-letter PDFs have a verified one-page A4 contract.

  5. Inspect the artifact and persist delivery

    Extract text, review every page visually, preserve file bytes and hashes, and verify all readiness gates before labeling the ticket ready.

Two scores, two meanings. The discovery relevance score selects jobs after hard gates. The CV emulator estimate compares document variants. Neither is the employer’s real ATS score, and neither predicts an interview. 01 12
07 / Observability

Numbers that explain the system.
Not numbers that flatter it.

A recorded worker snapshot shows operational activity. The separate dashboard uses stricter evidence to measure applications, networking and outcomes.

OPERATIONS / SNAPSHOT + DASHBOARD LOGICReconstructed case-study view · Not a live dashboard
Recorded + derived

5,190 known job identities

The sum of the worker’s current status buckets. This describes this workflow’s state—not every job available through AI Match.

Excluded2,427
Pending2,087
Fetched buffer600
Tracked46
Stretch23
Review7

Backlog: 2,087 pending + 600 fetched + 7 review + 0 selected = 2,694.

88.2/hObserved evaluation average

4,360 cumulative accepted evaluation events over 49.4 hours; repeats after context changes can count.

300/hBenchmark target, not achieved pace

A target for accepted complete evaluations—not application preparation or submissions.

A real limit is visible: recorded net drain was −68.6 items/hour over the observation window. New admissions and reopened work exceeded resolutions; the backlog was not shrinking. This snapshot does not establish the latest hour’s trend or whole-system health. 09
Dashboard configuration

A market radar without LLM calls

LATEST 30 VALIDATED JOBS SHOWN · A LIMIT, NOT A LIVE COUNT

01Two lanes: target titles + “typescript engineer”.
02Fully paginate the last 24 hours, 100 rows per page.
03Deduplicate IDs and apply local title/location rules.
04Count all validated results; display the newest 30.
05Refresh every 10 minutes; label cached-data errors.

“Relevant jobs · 24h” uses the complete validated result set. Company count, role mix and freshness use the latest-30 display sample. The radar’s broad remote filter is not the authoritative Spain-eligibility gate used in preparation. 10

Separate readers: Project data has a 5-minute cache. The market radar checks AI Match on each normal refresh and does not use an LLM.10 11

Submitted applications

Application track + an evidenced action date

Explicit Project dates, qualifying status-history transitions or approved owner evidence—not the creation of a ticket.

Interview conversion

Interviewed submitted applications ÷ submitted applications

Interview evidence is phase ≥1 or an interview status. The dashboard rounds the resulting percentage.

Ready to ship

Ready + open + no action date + no outcome

Restricted to application items. A raw GitHub “ready” label alone is not this complete calculation.

Application pace

Weekly submissions + four-week average

Uses action dates and UTC Monday week boundaries. The default goal is five/week, a configuration—not a reported result.

Source performance

Cold / referral / friend / recruiter

Source-specific interview rates use submitted applications. Networking outreach has a separate track and response-rate denominator.

Role & outcome safeguards

Prepared ≠ applied · Closed ≠ submitted

Product-management roles are filtered out; Product Engineer roles remain. Pre-submission withdrawals are not counted as applications.

Metric definitions are drawn from the dashboard’s actual data-mapping rules and TypeScript calculations. 10 11

What this snapshot deliberately does not invent

Live application, interview and offer totals were not reconstructed without the complete Project history. A separate GitHub search found 2 open tickets labeled “ready”; that is a raw label count, not a renewed validation of their application packs. No conversion uplift, time-saved percentage or full-market corpus total is claimed.

08 / The engineering lessons

The hard part is not the prompt.
It is making work resumable.

Every useful automation needs to distinguish “requested,” “in progress,” “actually completed,” and “we do not know.” This workflow makes those distinctions explicit. 08

What makes the design useful

01
State survives the conversation.

GitHub issues carry the queue; versioned sidecars, immutable requests and receipts let later invocations resume rather than start over.

02
Discovery cannot take over preparation.

Separate mode leases and per-issue ownership protect boundaries. Older executable work remains eligible even when new matches arrive.

03
Actions does mechanical work.

Fetching, hashing, packet preparation and independent validation move out of repeated assistant bookkeeping. Semantic judgments remain in ChatGPT.

04
One result, one consolidated report.

The orchestrator suppresses specialist chatter, persists the intended notification and retains the actual delivery receipt.

What it does not magically solve

Throughput and source freshness still matter.

Provider sync, queue load, rescoring and preparation all add latency. An hourly schedule is not proof that every role will be application-ready in a day.

Evidence can be missing or inaccessible.

A failed page fetch is not proof a role is closed. Genuine unknowns stay visible, and unsupported experience claims are omitted or asked about.

Delivery is not inherently exactly-once.

The Telegram relay’s in-memory duplicate guard is best-effort. Persisted intent and cautious recovery reduce risk; ambiguous sends are not blindly repeated.

A manifest is not a deployment certificate.

Version pins and contracts matter. The repository has some older README wording; the active schedules and current 4.1.0 policy take precedence here.

Technical appendix / State ownership & recovery

The discovery data plane

The assistant commits immutable requests and semantic decisions to main:automation/requests/ and automation/decisions/. Actions is the sole writer of job-discovery-state:runs/worker/, including state, index, cached postings, packets and acceptance receipts. The old main:runs/discovery/state.json is frozen after migration; reading it can give a stale view. The recorded index has eight discovery query families: six with hourly intervals, and leadership plus DevTools/DevRel with six-hour intervals. These are separate from the dashboard’s two radar lanes. 08 09

The preparation control plane

Mode and per-issue leases use blob-SHA compare-and-swap and read-back. Exact-input evidence controls reuse and invalidation. Render intents are persisted before dispatch; “recover” and “reuse” never authorize another render. Final lifecycle and comments are re-read before reporting blockers or readiness. 15

Independent validation

Actual worker receipts are required for issue-state and final-text Vale validation. A request file or successful workflow dispatch is not a passing receipt. Schema validity does not replace narrative evidence, optimization, visual PDF review or durable file delivery. 01 08 15

The email feedback loop

An overlapping 13-hour window reduces missed-message risk, while a Gmail-message-ID marker in the issue prevents repeated logging. Ambiguous company/role matches are surfaced instead of guessed. Read/unread state is not a processing cursor, and Spam is searched separately. 15

Technical appendix / GitHub Actions & packaging inventory

In the job-search repository

  • job-discovery-worker.yml
  • job-application-validation.yml
  • job-discovery-worker-tests.yml
  • job-search-assistant.yml
  • job-search-dashboard.yml
  • orchestrator-skills.yml
  • writing-style-rules.yml

Runtime workers, service/dashboard checks, skill contract checks and import-package generation have separate workflows. Listing a workflow does not prove its last run passed. 13

In the canonical website repository

  • render-resume-pdf.yml
  • render-cover-letter-pdf.yml
  • resume-lint.yml

The CV source stays in src/pages/resume.mdx. The document MCP requests these renderers instead of duplicating the CV design. The services and scheduled workflow use canonical, validated inputs and record render results. 03 14

The point of the project

Less copy-paste.
More intentional applications.

I designed this workflow to connect the parts of job searching that otherwise repeat in every tab: discovery, research, CV edits, forms and follow-up. It saves me repetitive work while keeping me in control. The time saving is real to me; the hours have not been measured.

Workflow design: Sandoche. Implementation: ChatGPT under Sandoche’s direction. AI Match was originally built by a friend; Sandoche extended it to access more opportunities. 12

Evidence, not a sales demo.

Sources and definitions behind this case study. Private repository links require authorized access.

Open the source ledger 18 sources · pinned code + recorded state + task configuration
  1. S01
    Orchestrator 4.1.0

    Mode boundaries, eligibility, quality gates, optional cover-letter destinations, and the prohibition on scheduled submission.

    .agents/skills/job-search-orchestrator/SKILL.md ↗
  2. S02
    Versioned skill inventory

    11 repository skills and their versions. This is not verification of every installed skill ZIP.

    .agents/skills/manifest.json ↗
  3. S03
    CV, cover-letter & narrative service

    Canonical CV source, 11 MCP tools, evidence requirements, validation and website-rendered PDFs.

    services/job-search-assistant/README.md ↗
  4. S04
    Telegram relay

    Three tools; fixed destination; rich text and photos; read-only status; best-effort duplicate protection. Main inspected on 12 September 2026.

    telegram-relay-richmarkdown-mcp / README.md ↗
  5. S05
    AI Match ingestion runtime

    Eight wired source adapters, Effect, BullMQ/Redis, PostgreSQL and provider worker loops. Source code, not a production health check.

    packages/sync/src/sync-queues/index.ts ↗
  6. S06
    AI Match ingestion policy

    Three-hour provider sweep and a 24-hour acknowledgement window after successful sync.

    packages/shared/src/jobSyncPolicy.ts ↗
  7. S07
    AI Match MCP handlers

    Search pagination and full-posting retrieval backed by the database. The exposed tool schemas confirm 100 search rows/page and 5 detail IDs/call.

    packages/mcp/src/handlers.ts ↗
  8. S08
    Worker & durable-state architecture

    Current two-mode design, single-writer discovery state, immutable signals, receipts and the 300/hour benchmark. Older sections are explicitly historical.

    automation/README.md ↗
  9. S09
    Recorded discovery-state snapshot

    Values captured from the index timestamp 2026-09-12T09:38:01.199755Z. This link follows a changing branch; the local snapshot.json preserves the cited aggregates.

    job-discovery-state:runs/worker/index.json ↗
  10. S10
    Dashboard architecture & mapping

    Read-only Project 10 dashboard; application-date evidence; market radar; role filters; caches and error states.

    apps/job-search-dashboard/README.md ↗
  11. S11
    Dashboard metric formulas

    Submitted, interview, source performance, pace and ready-to-ship calculations. Live Project history was not exported for this showcase.

    apps/job-search-dashboard/src/lib/metrics.ts ↗
  12. S12
    Ownership & measured-outcome limits

    Sandoche designed the workflow, ChatGPT implemented it under his direction; a friend originally built AI Match. Time savings are qualitative, not measured.

    experiences/ai-application-workflow/README.md ↗
  13. S13
    Job-search Actions inventory

    Discovery worker, independent validation, service/dashboard checks and skill/style packaging workflows.

    .github/workflows/ ↗
  14. S14
    Canonical website PDF workflows

    render-resume-pdf.yml, render-cover-letter-pdf.yml and resume-lint.yml. Master inspected on 12 September 2026.

    Sandoche-Website / .github/workflows/ ↗
  15. S15
    Active scheduled-task inspection

    Discovery hourly at :00 and preparation at :30 (Atlantic/Canary); email watch hourly (Europe/Paris). All three enabled. Configuration is not a guarantee of a completed run.

    ChatGPT scheduled tasks · inspected 12 September 2026
  16. S16
    Open ready-label count

    Search returned total_count=2 and incomplete_results=false. This is a raw label count, not a fresh readiness audit or the dashboard readyToShip metric.

    GitHub issue search · inspected 12 September 2026 ↗
  17. S17
    MCP architecture, in plain terms

    Host, client, server and tool responsibilities. MCP connects capabilities; it is not the reasoning model.

    Model Context Protocol · official architecture documentation ↗
  18. S18
    Pinned discovery execution contract

    Orchestrator 4.1.0, strict relevance >70 selection, independent mode ownership, timing budget and actual-receipt requirements.

    automation/cron-discovery.txt ↗

This is an offline, read-only showcase. Opening it does not connect to GitHub, Gmail, Telegram or any employer. Source links are optional external navigation. No credential, private email body or candidate answer is embedded. The interactive tour uses a fictional role.