job-application-agent 3.1.1 → 3.2.0
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 +11 -2
- package/job-application-agent/SKILL.md +29 -19
- package/job-application-agent/references/ANALYTICS.md +4 -0
- package/job-application-agent/references/RUNS.md +2 -1
- package/job-application-agent/references/SCHEMAS.md +8 -3
- package/job-application-agent/references/SOURCES.json +156 -0
- package/job-application-agent/references/SOURCES.md +73 -0
- package/job-application-agent/scripts/job-application.mjs +286 -23
- package/job-application-agent/scripts/source-community-client.mjs +338 -0
- package/job-application-agent/scripts/source-community-schema.mjs +320 -0
- package/job-application-agent/scripts/telemetry-client.mjs +3 -1
- package/job-application-agent/scripts/version.mjs +1 -0
- package/job-application-agent/tests/job-application.test.mjs +12 -9
- package/job-application-agent/tests/privacy-audit.test.mjs +39 -0
- package/job-application-agent/tests/source-community-client.test.mjs +351 -0
- package/job-application-agent/tests/source-community-schema.test.mjs +270 -0
- package/job-application-agent/tests/telemetry-client.test.mjs +1 -1
- package/job-application-agent/tests/version.test.mjs +12 -0
- package/job-application-agent/tests/workflow-state.test.mjs +506 -7
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -35,6 +35,7 @@ After onboarding, use natural commands:
|
|
|
35
35
|
|
|
36
36
|
```text
|
|
37
37
|
search jobs
|
|
38
|
+
list discovery sources for India and global remote engineering
|
|
38
39
|
apply https://company.example/jobs/123
|
|
39
40
|
apply all relevant jobs from this thread: <URL>
|
|
40
41
|
run a round of 10
|
|
@@ -48,7 +49,7 @@ Requires Node.js 20 or newer and a browser-capable coding agent.
|
|
|
48
49
|
|
|
49
50
|
| Stage | Behavior |
|
|
50
51
|
|---|---|
|
|
51
|
-
| **Discover** | Searches direct
|
|
52
|
+
| **Discover** | Searches a shared, versioned catalog of direct careers, ATS platforms, networks, feeds, and job boards, then verifies every lead at the employer. |
|
|
52
53
|
| **Qualify** | Checks seniority, skills, location, authorization, compensation, and posting status. |
|
|
53
54
|
| **Apply** | Fills forms and uploads one canonical résumé using verified facts only. |
|
|
54
55
|
| **Track** | Deduplicates applications and records only visible submission confirmations. |
|
|
@@ -101,6 +102,8 @@ flowchart LR
|
|
|
101
102
|
|
|
102
103
|
The bundled CLI handles private profile storage, résumé import, scoring, duplicate checks, resumable rounds, attention queues, and application/outcome ledgers. The coding agent handles discovery and browser interaction under the rules in [`SKILL.md`](job-application-agent/SKILL.md).
|
|
103
104
|
|
|
105
|
+
Discovery combines the reviewed [`SOURCES.json`](job-application-agent/references/SOURCES.json) catalog with an anonymous community registry. Every confirmed application automatically contributes its canonical public job URL, company, role, application channel, and provider; prior confirmed ledger entries backfill during later commands after a one-command disclosure grace period. Jobs, repeatable boards, and feeds are logged pending and become visible in the public dashboard or CLI only after maintainer review. Disable both forms of community sharing independently from analytics with `sources sharing disable`.
|
|
106
|
+
|
|
104
107
|
## 🔐 Privacy
|
|
105
108
|
|
|
106
109
|
| Data | Where it stays |
|
|
@@ -108,15 +111,21 @@ The bundled CLI handles private profile storage, résumé import, scoring, dupli
|
|
|
108
111
|
| Profile | macOS Keychain or Windows Credential Manager |
|
|
109
112
|
| Résumé and ledgers | Owner-only local state directory |
|
|
110
113
|
| Browser login | Existing browser session |
|
|
114
|
+
| Community-sharing preference and delivery receipts | Owner-only local state directory |
|
|
111
115
|
| Skill code | Version-controlled installation directory |
|
|
112
116
|
|
|
113
117
|
Candidate data, résumés, application history, credentials, and browser sessions are never committed to this repository.
|
|
114
118
|
|
|
115
119
|
Anonymous structured analytics are enabled by default to improve the agent. They may include job and workflow categories, but never candidate identity, résumé content, prompts, answers, browser data, IP addresses, or raw errors.
|
|
116
120
|
|
|
121
|
+
Anonymous community sharing is also enabled by default, separately from analytics. Confirmed applications share only a canonical public job URL, company, role, application channel, optional coarse discovery source, and derived provider URL—never candidate identity, answers, résumé, score, referral parameters, or submission timestamp. Repeatable discovery surfaces share their bounded catalog metadata through a maintainer-review queue. The registry stores no raw installation IDs; record-scoped contributor hashes are used only for deduplication and counts, never as identity or publication authority.
|
|
122
|
+
|
|
117
123
|
```bash
|
|
118
124
|
node ~/.agents/skills/job-application-agent/scripts/job-application.mjs telemetry status
|
|
119
125
|
node ~/.agents/skills/job-application-agent/scripts/job-application.mjs telemetry disable
|
|
126
|
+
node ~/.agents/skills/job-application-agent/scripts/job-application.mjs sources sharing status
|
|
127
|
+
node ~/.agents/skills/job-application-agent/scripts/job-application.mjs sources sharing disable
|
|
128
|
+
node ~/.agents/skills/job-application-agent/scripts/job-application.mjs sources jobs
|
|
120
129
|
```
|
|
121
130
|
|
|
122
131
|
See [`ANALYTICS.md`](job-application-agent/references/ANALYTICS.md) for the event contract and retention policy, or view the [public aggregate dashboard](https://job-application-agent-telemetry.varora1406.workers.dev/).
|
|
@@ -143,7 +152,7 @@ Updates are staged and validated before replacement. Private candidate state liv
|
|
|
143
152
|
npm test
|
|
144
153
|
```
|
|
145
154
|
|
|
146
|
-
GitHub Actions validates the skill and runs the same test suite on every pull request. To try the workflow without installing, paste [`SHARE_PROMPT.md`](SHARE_PROMPT.md) into a new agent chat.
|
|
155
|
+
GitHub Actions validates the skill and runs the same test suite on every pull request. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the full local verification and review contract. To try the workflow without installing, paste [`SHARE_PROMPT.md`](SHARE_PROMPT.md) into a new agent chat.
|
|
147
156
|
|
|
148
157
|
## ⚖️ Responsible use
|
|
149
158
|
|
|
@@ -24,24 +24,27 @@ Use `scripts/job-application.mjs` for private state and deterministic checks. Re
|
|
|
24
24
|
5. Use `review-each` for per-application approval. Use `routine-auto` only when the current request authorizes the destination or batch and every automatic-eligibility condition passes.
|
|
25
25
|
6. When the candidate explicitly grants continuing autonomy, read [references/AUTONOMY.md](references/AUTONOMY.md) and persist it with `autonomy grant --stdin`. Do not repeat skill-level upload or submission approval prompts while the active grant and profile both use `routine-auto`.
|
|
26
26
|
7. Obey browser and tool confirmation requirements regardless of the stored mode or autonomy grant.
|
|
27
|
-
8. Disclose default-enabled structured anonymous analytics and the `telemetry disable` control. The CLI also displays
|
|
27
|
+
8. Disclose default-enabled structured anonymous analytics and the `telemetry disable` control. Disclose default-enabled anonymous community sharing of confirmed public job links and repeatable discovery sources, plus the independent `sources sharing disable` control. The CLI also displays these disclosures before the first eligible transmission.
|
|
28
28
|
|
|
29
29
|
Never store passwords, MFA codes, government IDs, demographic data, CAPTCHA answers, browser session data, or inferred candidate facts.
|
|
30
30
|
|
|
31
31
|
## Discover and assess
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
Read [references/SOURCES.md](references/SOURCES.md) before the first discovery pass in a workflow.
|
|
34
|
+
|
|
35
|
+
1. Run `sources jobs` for recently confirmed direct job links and `sources list` (optionally filtered) for the highest-signal packaged and maintainer-reviewed discovery sources. Resolve every lead to the direct employer or ATS page.
|
|
36
|
+
2. Attribute the lead with coarse `discoverySource`, stable packaged or community `discoverySourceId` when known, and independent `applicationChannel`. Treat a one-off user link as `user-supplied`. Whenever a user or agent discovers a repeatable public board, feed, directory, or careers index that is not already listed, run `sources suggest --stdin`; the CLI contributes its sanitized metadata by default unless community sharing has been disabled.
|
|
37
|
+
3. Verify the application channel immediately before assessment. Mark it `active`, `closed`, or `unclear`.
|
|
38
|
+
4. Classify eligibility only after checking residence, location, work authorization, sponsorship, schedule, and employment type.
|
|
39
|
+
5. Extract explicit seniority, experience range, work mode, locations, comparable published salary maximum, and all must-have requirements.
|
|
40
|
+
6. Classify each must-have as `met`, `partial`, `missing`, or `unclear`. Attach private, resume-backed evidence for `met` and `partial`; never invent evidence.
|
|
41
|
+
7. Run `score --stdin`. Apply the returned gate decision before considering the score:
|
|
39
42
|
- `exclude`: closed or stale channel, explicit ineligibility, excluded company/location, or incompatible work mode.
|
|
40
43
|
- `ask`: unclear posting status, eligibility, authorization, location/work mode, seniority, or requirement evidence.
|
|
41
44
|
- `skip`: explicit non-target seniority, comparable compensation below the configured floor, insufficient must-have coverage, or score below the manual-review floor.
|
|
42
45
|
- `review`: a candidate for manual review or routine auto-submission.
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
8. Treat `autoEligible: true` as necessary but not sufficient to submit. It requires all gates to pass, exact Senior/Staff alignment, score at least 80, at least 70% evidenced must-have coverage, and no material experience-range mismatch.
|
|
47
|
+
9. Keep scores from 70 through 79 in manual review. Do not auto-submit when must-have analysis is absent or uncertain.
|
|
45
48
|
|
|
46
49
|
Do not lower seniority, compensation, location, work mode, or evidence thresholds to increase volume. Unknown compensation does not exclude a role; pause if the application asks the candidate to state or accept compensation.
|
|
47
50
|
|
|
@@ -51,16 +54,17 @@ For batches, scheduled work, or resumable handoffs, read [references/RUNS.md](re
|
|
|
51
54
|
|
|
52
55
|
1. Recheck employer, title, direct domain, posting status, eligibility, and `autoEligible` immediately before submission.
|
|
53
56
|
2. Run `ledger check --stdin` with the internal ledger ID, canonical URL, employer job ID, company, and role when available. Review both requisition duplicate status and same-company history.
|
|
54
|
-
3. Stop on a hard duplicate. Treat a same-company/same-role
|
|
55
|
-
4.
|
|
56
|
-
5.
|
|
57
|
-
6.
|
|
58
|
-
7.
|
|
59
|
-
8.
|
|
60
|
-
9.
|
|
61
|
-
10.
|
|
62
|
-
11. Record
|
|
63
|
-
12.
|
|
57
|
+
3. Stop on a hard ledger-ID, canonical-URL, employer-job-ID, or requisition duplicate. Treat a same-company/same-role alias as a possible duplicate. Use `duplicateOverride: "NEW REQUISITION CONFIRMED"` only after verifying it is a distinct requisition.
|
|
58
|
+
4. For a genuinely different role at a previously applied company, follow `companyReapply`: proceed automatically only when it returns `eligible-after-cooldown` (15 full days since the latest company application and no recorded outcome). `cooldown-active` and `follow-up-present` require the candidate's explicit approval and `companyReapplyOverride: "CANDIDATE APPROVED EARLY REAPPLICATION"`.
|
|
59
|
+
5. Keep authentication in the existing browser session. Never inspect cookies, local storage, passwords, or session files.
|
|
60
|
+
6. Fill only explicit profile fields, candidate-provided answers, or facts verified in the canonical resume.
|
|
61
|
+
7. Follow [references/APPLICATION_GUIDANCE.md](references/APPLICATION_GUIDANCE.md) for narrative answers.
|
|
62
|
+
8. Upload only the canonical resume unless the candidate explicitly provides another attachment. Resolve its absolute path with `resume path`, then follow [references/BROWSER_UPLOADS.md](references/BROWSER_UPLOADS.md). Use the browser's privileged path-based upload capability first; treat a visible native file picker as a fallback.
|
|
63
|
+
9. Do not answer demographic questions. Stop for login/SSO/MFA, CAPTCHA, legal attestations, unclear authorization or compensation, sensitive identifiers, and judgment-only questions.
|
|
64
|
+
10. Verify every required field, answer, attachment, and disclosure. Submit when the current request or active autonomy grant authorizes it.
|
|
65
|
+
11. Record `submitted` only after visible success confirmation, using independent `discoverySource`, `discoverySourceId`, `applicationChannel`, and `roundId` values. `ledger add` automatically shares the sanitized public job metadata and durably retries on relay failure; do not run a separate manual contribution. Record no submission when confirmation is missing or ambiguous.
|
|
66
|
+
12. Record workflow telemetry with `telemetry record --stdin`. Let `ledger add` emit `application_submitted`; do not emit it twice. Pass job URLs and structured metrics only through documented transient fields.
|
|
67
|
+
13. Queue hard stops with `attention add --stdin` and continue elsewhere. Record reproducible general-purpose failures with `friction record --stdin`; improvement work must never delay application work.
|
|
64
68
|
|
|
65
69
|
## Outcomes and reviews
|
|
66
70
|
|
|
@@ -93,6 +97,12 @@ node scripts/job-application.mjs autonomy grant --stdin
|
|
|
93
97
|
node scripts/job-application.mjs autonomy status|preview|revoke
|
|
94
98
|
node scripts/job-application.mjs round start|complete --stdin
|
|
95
99
|
node scripts/job-application.mjs round status [round-id]
|
|
100
|
+
node scripts/job-application.mjs sources list [--stdin]
|
|
101
|
+
node scripts/job-application.mjs sources jobs [--stdin]
|
|
102
|
+
node scripts/job-application.mjs sources suggest --stdin
|
|
103
|
+
node scripts/job-application.mjs sources pending
|
|
104
|
+
node scripts/job-application.mjs sources sync
|
|
105
|
+
node scripts/job-application.mjs sources sharing status|enable|disable|reset
|
|
96
106
|
node scripts/job-application.mjs attention add|resolve --stdin
|
|
97
107
|
node scripts/job-application.mjs attention list
|
|
98
108
|
node scripts/job-application.mjs friction record --stdin
|
|
@@ -25,12 +25,16 @@ node scripts/job-application.mjs telemetry record --stdin
|
|
|
25
25
|
|
|
26
26
|
Telemetry is best effort. It has no offline queue, uses a short network timeout, and never changes the result of a job-application command.
|
|
27
27
|
|
|
28
|
+
Community sharing is a separate default-enabled feature with independent `sources sharing status|enable|disable|reset` controls. Confirmed applications contribute bounded public job metadata, while repeatable discovery sources use maintainer review. Neither sends analytics events nor stores a raw contributor identity with a record; a record-scoped HMAC is used only for deduplication and unique-system counting. See [`SOURCES.md`](SOURCES.md) for the exact public metadata contracts.
|
|
29
|
+
|
|
28
30
|
## Identity boundary
|
|
29
31
|
|
|
30
32
|
Analytics never includes the candidate's name, email, phone, exact address, profile URLs, candidate location, work authorization, personal compensation or compensation floor, target profile or thresholds, resume or attachments, must-have evidence or coverage details, rejection reasons, prompts, responses, job descriptions, form questions, drafted answers, notes, passwords, MFA, CAPTCHA, legal or demographic answers, browser data, IP address, request headers, user agent, or raw error messages.
|
|
31
33
|
|
|
32
34
|
Structured job context may include company, role title, canonical destination domain, a SHA-256 hash of the job URL after removing query parameters and fragments, bounded discovery source, ATS/application channel, job country, work mode, employment type, seniority, role family, published salary band, fit score, match/gap categories, workflow stages, field categories, pause reasons, submission result, outcome, bounded interview quality, and bounded interview failure point.
|
|
33
35
|
|
|
36
|
+
The more specific local `discoverySourceId` catalog attribution is not transmitted in v1.
|
|
37
|
+
|
|
34
38
|
Local attention details and friction evidence are never transmitted. Analytics may receive only their already-documented bounded stage, ATS, pause reason, result, and aggregate count fields.
|
|
35
39
|
|
|
36
40
|
Company and title values are bounded and rejected when they resemble an email, phone number, URL, LinkedIn profile, or GitHub profile.
|
|
@@ -14,13 +14,14 @@ Start input: `{ "requestedCount": 30 }`. Complete input: `{ "roundId": "round-..
|
|
|
14
14
|
|
|
15
15
|
Count only unique applications with a visible employer/ATS confirmation or a verified sent recruiting email that were also added to the ledger with the same `roundId`. Filled forms, blockers, drafts, unsent email, and ambiguous confirmations never count. `round complete` rejects an under-target round.
|
|
16
16
|
|
|
17
|
-
Run both company-level and requisition-level duplicate checks before filling and again immediately before transmission.
|
|
17
|
+
Run both company-level and requisition-level duplicate checks before filling and again immediately before transmission. Hard ledger-ID, canonical-URL, employer-job-ID, and requisition duplicates always stop. Same-role aliases require a verified distinct requisition and `NEW REQUISITION CONFIRMED`. A genuinely different role at the same company may proceed automatically only when `companyReapply.decision` is `eligible-after-cooldown`: 15 full days have passed since the latest company application and no outcome has been recorded. `cooldown-active` and `follow-up-present` require explicit candidate approval.
|
|
18
18
|
|
|
19
19
|
Resolve the canonical résumé with `resume path`, upload its absolute path through the browser’s privileged chooser first, and verify the filename and parsed fields. Use a visible native picker only as a fallback.
|
|
20
20
|
|
|
21
21
|
Store independent attribution on every new ledger row:
|
|
22
22
|
|
|
23
23
|
- `discoverySource`: where the lead was found (`linkedin`, `x`, `yc`, `hacker-news`, `job-board`, `direct-company`, `email`, `user-supplied`, `web-search`, or `other`).
|
|
24
|
+
- `discoverySourceId`: stable packaged catalog ID such as `yc-work-at-a-startup` or `hacker-news-who-is-hiring`, when known.
|
|
24
25
|
- `applicationChannel`: where it was submitted (`ashby`, `greenhouse`, `lever`, `workday`, `company`, `email`, and the other documented ATS values).
|
|
25
26
|
- `source`: the legacy-compatible application channel.
|
|
26
27
|
|
|
@@ -49,6 +49,7 @@ Treat `mustHaves[].evidence` as private resume analysis. It is used locally and
|
|
|
49
49
|
"description": "Posting text",
|
|
50
50
|
"source": "greenhouse",
|
|
51
51
|
"discoverySource": "linkedin",
|
|
52
|
+
"discoverySourceId": "linkedin-jobs-feed",
|
|
52
53
|
"applicationChannel": "greenhouse",
|
|
53
54
|
"url": "https://job-boards.greenhouse.io/example/jobs/123",
|
|
54
55
|
"postingStatus": "active",
|
|
@@ -72,7 +73,7 @@ Treat `mustHaves[].evidence` as private resume analysis. It is used locally and
|
|
|
72
73
|
|
|
73
74
|
Allowed sources: `linkedin`, `greenhouse`, `lever`, `ashby`, `workable`, `comeet`, `workday`, `rippling`, `smartrecruiters`, `google-form`, `company`, `email`, and `other`.
|
|
74
75
|
|
|
75
|
-
`source` remains the backward-compatible application channel. New workflows should also supply `discoverySource` (`direct-company`, `linkedin`, `x`, `yc`, `hacker-news`, `job-board`, `email`, `user-supplied`, `web-search`, or `other`) and `applicationChannel` using the allowed `source` values.
|
|
76
|
+
`source` remains the backward-compatible application channel. New workflows should also supply `discoverySource` (`direct-company`, `linkedin`, `x`, `yc`, `hacker-news`, `job-board`, `email`, `user-supplied`, `web-search`, or `other`), the kebab-case `discoverySourceId` from [`SOURCES.json`](SOURCES.json) when known, and `applicationChannel` using the allowed `source` values.
|
|
76
77
|
|
|
77
78
|
Allowed posting statuses: `active`, `closed`, `unclear`. Allowed eligibility: `eligible`, `unclear`, `ineligible`. Allowed seniority: `junior`, `mid`, `senior`, `staff`, `principal`, `lead`, `manager`, `director`, `founding`, `unspecified`. Allowed work modes: `remote`, `hybrid`, `onsite`, `unspecified`. Must-have statuses: `met`, `partial`, `missing`, `unclear`.
|
|
78
79
|
|
|
@@ -94,6 +95,8 @@ Include as many identifiers as are known.
|
|
|
94
95
|
|
|
95
96
|
The check removes fragments and non-job query parameters while retaining recognized job or requisition identifiers. Matching ledger ID, canonical URL, or same-company employer job ID is a hard duplicate. Same company and role without a shared job ID is a possible duplicate.
|
|
96
97
|
|
|
98
|
+
`ledger check` also returns `companyReapply`. A genuinely different role is `eligible-after-cooldown` only when at least 15 full days have passed since the latest application to that company and no outcome has been recorded for that application. Hard duplicates are never eligible. Same-role matches, `cooldown-active`, and `follow-up-present` remain blocked at `ledger add` unless their exact documented override is present.
|
|
99
|
+
|
|
97
100
|
## Confirmed submission input
|
|
98
101
|
|
|
99
102
|
Add only after visible success confirmation.
|
|
@@ -107,6 +110,7 @@ Add only after visible success confirmation.
|
|
|
107
110
|
"employerJobId": "greenhouse:123",
|
|
108
111
|
"source": "company",
|
|
109
112
|
"discoverySource": "x",
|
|
113
|
+
"discoverySourceId": "x-hiring-feed",
|
|
110
114
|
"applicationChannel": "company",
|
|
111
115
|
"roundId": "round-2026-01-15-00000000-0000-4000-8000-000000000000",
|
|
112
116
|
"score": 84,
|
|
@@ -114,6 +118,7 @@ Add only after visible success confirmation.
|
|
|
114
118
|
"submittedAt": "2026-01-15T10:00:00.000Z",
|
|
115
119
|
"approval": "STANDING AUTHORIZATION",
|
|
116
120
|
"duplicateOverride": "NEW REQUISITION CONFIRMED",
|
|
121
|
+
"companyReapplyOverride": "CANDIDATE APPROVED EARLY REAPPLICATION",
|
|
117
122
|
"answers": { "Resume": "Canonical resume.pdf" },
|
|
118
123
|
"telemetry": {
|
|
119
124
|
"durationBucket": "5-15m",
|
|
@@ -124,9 +129,9 @@ Add only after visible success confirmation.
|
|
|
124
129
|
}
|
|
125
130
|
```
|
|
126
131
|
|
|
127
|
-
Use `duplicateOverride` only for a verified distinct requisition after a possible-duplicate warning.
|
|
132
|
+
Use `duplicateOverride` only for a verified distinct requisition after a possible-duplicate warning. Use `companyReapplyOverride` only when the candidate explicitly approves a different-role reapplication during the cooldown or after a recorded outcome. Both override phrases and `telemetry` are transient. An accepted company reapplication override stores only `reapplicationApproval: "candidate-explicit"` in the private ledger. Use approval `APPROVE SUBMIT` for per-application approval or `STANDING AUTHORIZATION` when the current request authorizes routine batch submission.
|
|
128
133
|
|
|
129
|
-
`discoverySource`, `applicationChannel`, and `roundId` are optional for backward compatibility and should be supplied for new resumable rounds. `ledger check` returns hard
|
|
134
|
+
`discoverySource`, `discoverySourceId`, `applicationChannel`, and `roundId` are optional for backward compatibility and should be supplied for new resumable rounds. `discoverySourceId` accepts stable packaged and `community-…` source IDs; it remains local and is not included in telemetry. After a visibly confirmed submission, `ledger add` automatically contributes only the canonical public URL, company, role, application channel, optional coarse discovery source, and derived provider URL to the pending community job registry. Existing installations receive a one-command disclosure grace period before historical backfill; `sources sharing disable` opts out. The private answers, score, submission time, IDs, and round remain local, and no job appears publicly before maintainer review. `ledger check` returns hard duplicate status, bounded same-company history, and the same `companyReapply` decision enforced by `ledger add` while holding the application lock.
|
|
130
135
|
|
|
131
136
|
## Autonomy grant input
|
|
132
137
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "direct-company-careers",
|
|
4
|
+
"name": "Direct company careers pages",
|
|
5
|
+
"kind": "direct-employer",
|
|
6
|
+
"jobsUrl": null,
|
|
7
|
+
"regions": ["global"],
|
|
8
|
+
"roleFamilies": ["engineering"],
|
|
9
|
+
"requiresSession": false,
|
|
10
|
+
"access": "public",
|
|
11
|
+
"verification": "direct-employer-or-ats"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "linkedin-jobs-feed",
|
|
15
|
+
"name": "LinkedIn jobs, posts, and feed",
|
|
16
|
+
"kind": "professional-network",
|
|
17
|
+
"jobsUrl": "https://www.linkedin.com/jobs/",
|
|
18
|
+
"regions": ["global"],
|
|
19
|
+
"roleFamilies": ["engineering"],
|
|
20
|
+
"requiresSession": true,
|
|
21
|
+
"access": "session",
|
|
22
|
+
"verification": "direct-employer-or-ats"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "x-hiring-feed",
|
|
26
|
+
"name": "X hiring posts and feed",
|
|
27
|
+
"kind": "social-feed",
|
|
28
|
+
"jobsUrl": "https://x.com/home",
|
|
29
|
+
"regions": ["global"],
|
|
30
|
+
"roleFamilies": ["engineering"],
|
|
31
|
+
"requiresSession": true,
|
|
32
|
+
"access": "session",
|
|
33
|
+
"verification": "direct-employer-or-ats"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "yc-work-at-a-startup",
|
|
37
|
+
"name": "YC Work at a Startup",
|
|
38
|
+
"kind": "startup-network",
|
|
39
|
+
"jobsUrl": "https://www.workatastartup.com/jobs",
|
|
40
|
+
"regions": ["global", "india", "north-america"],
|
|
41
|
+
"roleFamilies": ["engineering"],
|
|
42
|
+
"requiresSession": true,
|
|
43
|
+
"access": "session",
|
|
44
|
+
"verification": "direct-employer-or-ats"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "yc-company-directory",
|
|
48
|
+
"name": "Y Combinator company hiring directory",
|
|
49
|
+
"kind": "startup-network",
|
|
50
|
+
"jobsUrl": "https://www.ycombinator.com/companies/hiring",
|
|
51
|
+
"regions": ["global", "india", "north-america"],
|
|
52
|
+
"roleFamilies": ["engineering"],
|
|
53
|
+
"requiresSession": false,
|
|
54
|
+
"access": "public",
|
|
55
|
+
"verification": "direct-employer-or-ats"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "hacker-news-who-is-hiring",
|
|
59
|
+
"name": "Hacker News Who is Hiring",
|
|
60
|
+
"kind": "community-thread",
|
|
61
|
+
"jobsUrl": "https://news.ycombinator.com/submitted?id=whoishiring",
|
|
62
|
+
"regions": ["global"],
|
|
63
|
+
"roleFamilies": ["engineering"],
|
|
64
|
+
"requiresSession": false,
|
|
65
|
+
"access": "public",
|
|
66
|
+
"verification": "direct-employer-or-ats"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": "we-work-remotely",
|
|
70
|
+
"name": "We Work Remotely",
|
|
71
|
+
"kind": "job-board",
|
|
72
|
+
"jobsUrl": "https://weworkremotely.com/remote-jobs/search?term=software+engineer",
|
|
73
|
+
"regions": ["global", "remote"],
|
|
74
|
+
"roleFamilies": ["engineering"],
|
|
75
|
+
"requiresSession": false,
|
|
76
|
+
"access": "public",
|
|
77
|
+
"verification": "direct-employer-or-ats"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"id": "a16z-build-jobs",
|
|
81
|
+
"name": "a16z Build open roles",
|
|
82
|
+
"kind": "curated-board",
|
|
83
|
+
"jobsUrl": "https://a16zbuild.substack.com/",
|
|
84
|
+
"regions": ["global", "north-america"],
|
|
85
|
+
"roleFamilies": ["engineering"],
|
|
86
|
+
"requiresSession": false,
|
|
87
|
+
"access": "public",
|
|
88
|
+
"verification": "direct-employer-or-ats"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "engg-space",
|
|
92
|
+
"name": "Engg.space",
|
|
93
|
+
"kind": "curated-board",
|
|
94
|
+
"jobsUrl": "https://www.engg.space/",
|
|
95
|
+
"regions": ["india", "global", "remote"],
|
|
96
|
+
"roleFamilies": ["engineering"],
|
|
97
|
+
"requiresSession": false,
|
|
98
|
+
"access": "public",
|
|
99
|
+
"verification": "direct-employer-or-ats"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "js-guru-jobs",
|
|
103
|
+
"name": "JS Guru Jobs",
|
|
104
|
+
"kind": "curated-board",
|
|
105
|
+
"jobsUrl": "https://jsgurujobs.com/jobs",
|
|
106
|
+
"regions": ["global", "remote"],
|
|
107
|
+
"roleFamilies": ["engineering"],
|
|
108
|
+
"requiresSession": true,
|
|
109
|
+
"access": "session",
|
|
110
|
+
"verification": "direct-employer-or-ats"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "linux-careers",
|
|
114
|
+
"name": "Linux Careers",
|
|
115
|
+
"kind": "job-board",
|
|
116
|
+
"jobsUrl": "https://www.linuxcareers.com/jobs",
|
|
117
|
+
"regions": ["global", "remote"],
|
|
118
|
+
"roleFamilies": ["engineering"],
|
|
119
|
+
"requiresSession": false,
|
|
120
|
+
"access": "public",
|
|
121
|
+
"verification": "direct-employer-or-ats"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"id": "indeed",
|
|
125
|
+
"name": "Indeed",
|
|
126
|
+
"kind": "job-board",
|
|
127
|
+
"jobsUrl": "https://www.indeed.com/",
|
|
128
|
+
"regions": ["global", "india"],
|
|
129
|
+
"roleFamilies": ["engineering"],
|
|
130
|
+
"requiresSession": true,
|
|
131
|
+
"access": "session",
|
|
132
|
+
"verification": "direct-employer-or-ats"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"id": "recruiter-inbound",
|
|
136
|
+
"name": "Verified recruiter email and direct messages",
|
|
137
|
+
"kind": "inbound",
|
|
138
|
+
"jobsUrl": null,
|
|
139
|
+
"regions": ["global"],
|
|
140
|
+
"roleFamilies": ["engineering"],
|
|
141
|
+
"requiresSession": true,
|
|
142
|
+
"access": "connector-or-session",
|
|
143
|
+
"verification": "direct-employer-or-ats"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"id": "user-supplied-leads",
|
|
147
|
+
"name": "User-supplied job links and hiring posts",
|
|
148
|
+
"kind": "user-supplied",
|
|
149
|
+
"jobsUrl": null,
|
|
150
|
+
"regions": ["global"],
|
|
151
|
+
"roleFamilies": ["engineering"],
|
|
152
|
+
"requiresSession": false,
|
|
153
|
+
"access": "candidate-provided",
|
|
154
|
+
"verification": "direct-employer-or-ats"
|
|
155
|
+
}
|
|
156
|
+
]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Discovery source registry
|
|
2
|
+
|
|
3
|
+
The packaged [`SOURCES.json`](SOURCES.json) catalog is the reviewed, versioned list of repeatable discovery surfaces available to every installation. A community registry supplements it with maintainer-reviewed discovery sources and direct public job links from confirmed applications. Both remain distinct from application channels such as Greenhouse, Ashby, Lever, and Workday.
|
|
4
|
+
|
|
5
|
+
## Use the catalog
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
node scripts/job-application.mjs sources list
|
|
9
|
+
node scripts/job-application.mjs sources list --stdin
|
|
10
|
+
node scripts/job-application.mjs sources jobs
|
|
11
|
+
echo '{"limit":25,"cursor":"opaque-cursor"}' | node scripts/job-application.mjs sources jobs --stdin
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Optional filter input:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"regions": ["india", "global", "remote"],
|
|
19
|
+
"roleFamilies": ["engineering"],
|
|
20
|
+
"kinds": ["job-board", "startup-network"],
|
|
21
|
+
"requiresSession": false
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`sources list` combines the packaged catalog with the live repeatable-source registry. Public v1 community entries are always maintainer-approved and have `registryStatus: "community-reviewed"`. Their `id` and `communitySourceId` are the same stable community ID and may be stored as `discoverySourceId`. `sources jobs` returns the newest maintainer-reviewed confirmed job links, 50 at a time by default, with an opaque `nextCursor` for pagination. Both are discovery leads, not endorsements or eligibility claims. Resolve every lead to the direct employer or ATS page and verify that posting immediately before assessment and submission.
|
|
26
|
+
|
|
27
|
+
Store three independent attribution fields when available:
|
|
28
|
+
|
|
29
|
+
- `discoverySource`: coarse compatible channel such as `linkedin`, `x`, `yc`, `job-board`, or `user-supplied`.
|
|
30
|
+
- `discoverySourceId`: stable packaged or community ID such as `yc-work-at-a-startup` or `community-abcdef1234567890`.
|
|
31
|
+
- `applicationChannel`: actual submission channel such as `greenhouse`, `ashby`, `lever`, `company`, or `email`.
|
|
32
|
+
|
|
33
|
+
`discoverySourceId` remains local in v1 and is not transmitted by telemetry.
|
|
34
|
+
|
|
35
|
+
## Community sharing
|
|
36
|
+
|
|
37
|
+
Community sharing is enabled by default and independent of usage analytics. A confirmed `ledger add` queues and attempts the sanitized public job metadata automatically. Installations with historical applications consume one full disclosure command without transmission before backfill, giving them time to run `sources sharing disable`; an explicit `sources sharing enable` opts in immediately. New installations have no historical backfill and contribute the first newly confirmed job after displaying the notice. Existing confirmed ledger entries are the durable backfill/retry queue and are retried in bounded batches during later commands. No separate contribution command is required for applied jobs.
|
|
38
|
+
|
|
39
|
+
Whenever the user or agent discovers a repeatable public discovery surface—not a recruiter profile, referral link, personal URL, or one-off job detail route—queue it for maintainer review:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
node scripts/job-application.mjs sources suggest --stdin
|
|
43
|
+
node scripts/job-application.mjs sources pending
|
|
44
|
+
node scripts/job-application.mjs sources sync
|
|
45
|
+
node scripts/job-application.mjs sources jobs
|
|
46
|
+
node scripts/job-application.mjs sources sharing status
|
|
47
|
+
node scripts/job-application.mjs sources sharing disable
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Suggestion input:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"name": "Example Engineering Board",
|
|
55
|
+
"baseUrl": "https://jobs.example.org/openings/engineering",
|
|
56
|
+
"kind": "job-board",
|
|
57
|
+
"regions": ["global"],
|
|
58
|
+
"roleFamilies": ["engineering"],
|
|
59
|
+
"requiresSession": false
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The first eligible contribution displays a disclosure and sends during that command. `disable` stops both job and discovery-source sharing; `enable` resumes and retries it; `reset` disables sharing and removes its anonymous relay credentials. The preference, anonymous credential, and delivery receipts are stored in owner-only local files.
|
|
64
|
+
|
|
65
|
+
The applied-job contract contains only the canonical HTTPS job URL, company, role, application channel, optional coarse discovery source, and a server-derived provider URL. Referral, tracking, and fragment data are removed; a small allowlist of stable job/requisition query identifiers is retained so query-addressed jobs do not collapse together. The server adds day-bucketed first/last-seen dates and an anonymous agent-report count. Candidate identity, résumé, form answers, score, application timestamp, referral parameters, raw installation ID, and contributor hash are never public or stored with a community job. Every accepted record is logged as pending; only a maintainer-reviewed destination and matching company/role can become public. Canonical URL deduplication prevents repeated rows, and rejected records never republish automatically.
|
|
66
|
+
|
|
67
|
+
The client and relay use the same fail-closed source-route classifier. They remove query parameters and fragments; reject embedded credentials, credential-like opaque path segments, identity-like names and paths, personal profiles, local/private hosts, unknown fields, oversized payloads, and known detail routes from Workday, LinkedIn Jobs, Greenhouse, Lever, Ashby, Workable, and SmartRecruiters. Unknown domains are accepted only at the root or on explicit collection, directory, feed, careers, openings, or job-index routes. Only the source name, canonical public base URL, kind, regions, role families, and session requirement are shared.
|
|
68
|
+
|
|
69
|
+
The raw anonymous installation ID authenticates and rate-limits a request but is never stored in the registry. The relay stores a source-scoped HMAC only to deduplicate contributions and help a maintainer prioritize review. One system contributes at most once to a canonical source, and `contributionCount` always means unique contributing systems—not people. It is never identity, trust, authority, or a condition for publication. The first valid contribution owns the canonical metadata; later contributions cannot rewrite it.
|
|
70
|
+
|
|
71
|
+
If sharing is disabled or offline, repeatable-source suggestions remain in their owner-only queue and confirmed jobs remain pending in the canonical ledger until a minimal delivery receipt exists. `sources pending` reports both kinds of locally unsent work. `sources sync` retries both, and `sources list` performs a best-effort retry before reading the registry. A server-accepted source suggestion is delivered even while pending moderation. Network failure never blocks discovery or an application.
|
|
72
|
+
|
|
73
|
+
Every accepted repeatable-source contribution remains in the private moderation queue until an owner explicitly approves it with owner-only D1 commands. Rejected sources remain hidden after later contributions and cannot republish automatically. Maintainer procedures are documented in [`telemetry-worker/COMMUNITY_SOURCE_MODERATION.md`](https://github.com/vaibhavarora14/job-application-agent/blob/main/telemetry-worker/COMMUNITY_SOURCE_MODERATION.md). This moderation rule does not delay sanitized confirmed-job links.
|