Designing a Machine-to-Machine Job Application Protocol
The Problem
Job applications today are a manual, browser-bound chore. You fill out the same fields a hundred times, solve CAPTCHAs that prove you’re human (but waste your time), upload the same PDF to every portal, and wait. The process assumes a human on both sides.
But what if neither side needs to be human at the application stage?
The headhunter-agent project already eliminates the browser on the candidate side: it’s a native Clojure/JavaFX desktop app that evaluates job postings, profiles candidates, and generates tailored PDFs — all without a web browser. The missing piece was an employer-facing protocol that closes the loop: machine-readable job postings, automated discovery, and signed application submission.
This post describes the M2M Job Application Protocol v1.0.0: a full-stack protocol for machine-to-machine recruiting, designed as an extension to headhunter-agent.
System Context
The protocol connects four actors:
The Four Sub-Protocols
The M2M protocol decomposes into four sub-protocols that execute in sequence:
1. Discovery — DNS TXT Records
No central registry. No API keys. No sign-ups.
Employers publish a single DNS TXT record on their domain:
The TXT record format is intentionally simple:
A Babashka fallback directory service aggregates known endpoints for discovery when DNS is unavailable:
2. Fetch — Machine-Readable Job Postings
Employers serve job postings as JSON-LD over HTTPS. The schema extends schema.org/JobPosting with M2M-specific fields for protocol metadata:
The JSON-LD posting carries everything a machine needs: title, description, skills, compensation range, and crucially, the application endpoint and employer public key.
3. Verify — Cryptographic Handshake
Every participant generates an Ed25519 keypair. No CA hierarchy, no certificate authorities. Trust is established through DNS binding:
Applications are signed at two levels:
- Envelope signature: canonical JSON of the entire package (minus the signature field) is signed with Ed25519
- Attachment signature: each file’s SHA-256 digest is independently signed, enabling individual file verification
4. Submit — Signed Application Delivery
The signed package is delivered as a multipart HTTP POST:
The employer responds with a signed acknowledgment:
Full Data Flow
Here’s the complete flow from discovery to submission:
Protocol Stack
Application Lifecycle State Machine
Implementation Architecture
The protocol is implemented as eight Clojure namespaces under
career-ops.m2m, extending the existing
headhunter-agent:
Each namespace has a single responsibility:
| Module | File | Lines | Responsibility |
|---|---|---|---|
core |
core.clj |
159 | CLI routing for
bb m2m {keygen,discover,fetch,apply,verify,serve} |
crypto |
crypto.clj |
133 | Ed25519 key generation, signing, verification, SHA-256 digests, canonical JSON |
schema |
schema.clj |
106 | JSON-LD @context, structural validation for all message types |
registry |
registry.clj |
85 | DNS TXT lookup + HTTP directory fallback |
fetch |
fetch.clj |
66 | Job posting HTTP fetcher with schema validation |
submit |
submit.clj |
91 | Application package assembly, attachment signing, multipart POST |
verify |
verify.clj |
82 | Inbound envelope + attachment signature verification |
directory |
directory.clj |
76 | Optional Babashka HTTP directory aggregator server |
CLI Usage
The protocol is exposed through a unified CLI:
The bb m2m apply command chains the entire pipeline:
- Discover — DNS lookup for employer endpoint
- Fetch — HTTP GET for JSON-LD job posting
- Evaluate — Existing 3-stage MAS pipeline (legitimacy, fit, cheat sheet)
- Tailor — Gemini-powered resume tailoring, compiled via Typst
- Sign — Ed25519 signature on package + attachment digests
- Submit — Multipart POST to employer endpoint
- Acknowledge — Verify employer’s signed receipt
Security Model
| Threat | Mitigation |
|---|---|
| Employer impersonation | DNS TXT binds public key to domain; TLS validates transport |
| Candidate impersonation | Ed25519 signature on every application envelope |
| Replay attack | Timestamps + server-enforced freshness window |
| Tampered resume | Per-attachment SHA-256 digest + independent Ed25519 signature |
| Man-in-the-middle | TLS 1.3 for all HTTP; signatures provide end-to-end integrity |
| Registry poisoning | Directory entries are signed; primary discovery is DNS (DNSSEC-ready) |
No-CAPTCHA Guarantee
The protocol explicitly eliminates all human verification:
- Endpoints opt in by publishing
m2m:acceptsSignedApplications: true - Signed identity replaces cookies, sessions, and auth walls
- Rate limiting is by public key fingerprint, not IP address
- Reputation is based on application quality, not manual review
Protocol Extension Points
Integration with headhunter-agent
The protocol extends the existing project without breaking any existing functionality:
The existing MAS pipeline (Legitimacy check → Fit Analysis → Cheat Sheet) remains unchanged. The M2M module calls it as a step in the apply workflow, then adds signing and submission on top.
Implementation Roadmap
The protocol is designed for incremental delivery:
| Phase | Components | Dependency |
|---|---|---|
| P0 | crypto.clj, schema.clj,
core.clj (keygen + verify) |
None |
| P1 | registry.clj (DNS), fetch.clj |
P0 |
| P2 | submit.clj, verify.clj |
P0, P1 |
| P3 | directory.clj |
P0 |
| P4 | Full bb m2m apply with MAS pipeline |
P0-P3 |
| P5 | Employer-side verification library | P0, P2 |
The Bigger Picture
The M2M Job Application Protocol is a small piece of a larger vision: moving all white-collar recruiting from human-mediated workflows to autonomous agent coordination.
The protocol is:
- Local-first: all candidate data stays on-device until the moment of submission
- Privacy-preserving: no third-party job boards, no data brokers, no resume databases
- Decentralized: no central authority required — DNS is the registry
- Cryptographically verifiable: every message carries proof of origin and integrity
- Extension-ready: the JSON-LD schemas and protocol messages are designed for forward compatibility
The specification and implementation are part of the headhunter-agent project, which is MIT-licensed open source.
For the full protocol specification, including detailed message formats, schema definitions, and the complete Clojure implementation, see the repository at gitlab.com/nurazhar/headhunter-agent.