job-forge 2.14.38 → 2.14.40
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/.codex/config.toml +3 -2
- package/.cursor/mcp.json +8 -3
- package/.cursor/rules/main.mdc +1 -1
- package/.mcp.json +8 -3
- package/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/README.md +143 -191
- package/batch/README.md +1 -1
- package/bin/create-job-forge.mjs +8 -4
- package/bin/geometra-mcp-launcher.mjs +86 -0
- package/bin/job-forge.mjs +3 -0
- package/bin/sync.mjs +1 -1
- package/docs/ARCHITECTURE.md +20 -20
- package/docs/CUSTOMIZATION.md +20 -20
- package/docs/README.md +1 -1
- package/docs/SETUP.md +3 -3
- package/iso/instructions.md +1 -1
- package/iso/mcp.json +5 -1
- package/lib/jobforge-cache.mjs +1 -1
- package/lib/jobforge-canon.mjs +1 -1
- package/lib/jobforge-capabilities.mjs +1 -1
- package/lib/jobforge-context.mjs +1 -1
- package/lib/jobforge-contracts.mjs +1 -1
- package/lib/jobforge-facts.mjs +1 -1
- package/lib/jobforge-index.mjs +1 -1
- package/lib/jobforge-ledger.mjs +1 -1
- package/lib/jobforge-lineage.mjs +1 -1
- package/lib/jobforge-migrate.mjs +1 -1
- package/lib/jobforge-observability.mjs +1 -1
- package/lib/jobforge-postflight.mjs +1 -1
- package/lib/jobforge-preflight.mjs +1 -1
- package/lib/jobforge-prioritize.mjs +1 -1
- package/lib/jobforge-redact.mjs +1 -1
- package/lib/jobforge-score.mjs +1 -1
- package/lib/jobforge-timeline.mjs +1 -1
- package/models.yaml +1 -1
- package/modes/batch.md +1 -1
- package/modes/reference-portals.md +3 -1
- package/modes/reference-setup.md +1 -1
- package/opencode.json +7 -3
- package/package.json +26 -26
- package/scripts/batch-orchestrator.mjs +2 -2
- package/scripts/cache.mjs +1 -1
- package/scripts/canon.mjs +1 -1
- package/scripts/check-helper-integration.mjs +19 -19
- package/scripts/facts.mjs +1 -1
- package/scripts/guard.mjs +1 -1
- package/scripts/index.mjs +1 -1
- package/scripts/ledger.mjs +1 -1
- package/scripts/lineage.mjs +1 -1
- package/scripts/migrate.mjs +1 -1
- package/scripts/postflight.mjs +1 -1
- package/scripts/preflight.mjs +1 -1
- package/scripts/prioritize.mjs +1 -1
- package/scripts/redact.mjs +1 -1
- package/scripts/score.mjs +1 -1
- package/scripts/timeline.mjs +1 -1
- package/scripts/trace.mjs +1 -1
- package/templates/portals.example.yml +1 -1
package/.codex/config.toml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# generated by @
|
|
1
|
+
# generated by @agent-pattern-labs/iso-route — do not hand-edit
|
|
2
2
|
model = "gpt-5.4"
|
|
3
3
|
model_provider = "openai"
|
|
4
4
|
|
|
@@ -17,7 +17,8 @@ model_provider = "openai"
|
|
|
17
17
|
|
|
18
18
|
[mcp_servers.geometra]
|
|
19
19
|
command = "npx"
|
|
20
|
-
args = ["-
|
|
20
|
+
args = ["--no-install", "job-forge", "mcp:geometra"]
|
|
21
|
+
env = { GEOMETRA_STEALTH = "1", GEOMETRA_BROWSER = "stealth" }
|
|
21
22
|
|
|
22
23
|
[mcp_servers.gmail]
|
|
23
24
|
command = "npx"
|
package/.cursor/mcp.json
CHANGED
|
@@ -3,9 +3,14 @@
|
|
|
3
3
|
"geometra": {
|
|
4
4
|
"command": "npx",
|
|
5
5
|
"args": [
|
|
6
|
-
"-
|
|
7
|
-
"
|
|
8
|
-
|
|
6
|
+
"--no-install",
|
|
7
|
+
"job-forge",
|
|
8
|
+
"mcp:geometra"
|
|
9
|
+
],
|
|
10
|
+
"env": {
|
|
11
|
+
"GEOMETRA_STEALTH": "1",
|
|
12
|
+
"GEOMETRA_BROWSER": "stealth"
|
|
13
|
+
}
|
|
9
14
|
},
|
|
10
15
|
"gmail": {
|
|
11
16
|
"command": "npx",
|
package/.cursor/rules/main.mdc
CHANGED
|
@@ -56,7 +56,7 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
|
|
|
56
56
|
- [D6] Pick the mode from the **Routing** table below AND name it explicitly in your first response (e.g., "running auto-pipeline mode", "this is a `compare` request"). If no row matches the user's intent, ask which mode fits; do not guess.
|
|
57
57
|
why: silent mode picks mis-route work (a "negotiation" question answered in `offer` mode produces the wrong report shape); naming the mode out loud makes the routing decision reviewable and gives downstream dispatches a reliable anchor
|
|
58
58
|
|
|
59
|
-
- [D7] For standalone `batch` runs, prefer `batch/batch-runner.sh` instead of hand-rolling the loop. It delegates to `@
|
|
59
|
+
- [D7] For standalone `batch` runs, prefer `batch/batch-runner.sh` instead of hand-rolling the loop. It delegates to `@agent-pattern-labs/iso-orchestrator`, persists workflow records in `.jobforge-runs/`, caps bundle fan-out, and mutexes state/report-number writes. Use `JOBFORGE_LEGACY_BATCH_RUNNER=1` only as a fallback.
|
|
60
60
|
why: the old Bash loop encoded resumability and parallelism manually; the iso-orchestrator path makes the durable control state inspectable and prevents report-number collisions under parallel bundles
|
|
61
61
|
|
|
62
62
|
- [D8] Use deterministic local helpers instead of prose when they can answer or validate state, identity, policy, scoring, timing, dispatch, priority, lineage, migration, or safe-export questions. Read `modes/reference-local-helpers.md` when choosing a helper or changing helper wiring.
|
package/.mcp.json
CHANGED
|
@@ -3,9 +3,14 @@
|
|
|
3
3
|
"geometra": {
|
|
4
4
|
"command": "npx",
|
|
5
5
|
"args": [
|
|
6
|
-
"-
|
|
7
|
-
"
|
|
8
|
-
|
|
6
|
+
"--no-install",
|
|
7
|
+
"job-forge",
|
|
8
|
+
"mcp:geometra"
|
|
9
|
+
],
|
|
10
|
+
"env": {
|
|
11
|
+
"GEOMETRA_STEALTH": "1",
|
|
12
|
+
"GEOMETRA_BROWSER": "stealth"
|
|
13
|
+
}
|
|
9
14
|
},
|
|
10
15
|
"gmail": {
|
|
11
16
|
"command": "npx",
|
package/AGENTS.md
CHANGED
|
@@ -51,7 +51,7 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
|
|
|
51
51
|
- [D6] Pick the mode from the **Routing** table below AND name it explicitly in your first response (e.g., "running auto-pipeline mode", "this is a `compare` request"). If no row matches the user's intent, ask which mode fits; do not guess.
|
|
52
52
|
why: silent mode picks mis-route work (a "negotiation" question answered in `offer` mode produces the wrong report shape); naming the mode out loud makes the routing decision reviewable and gives downstream dispatches a reliable anchor
|
|
53
53
|
|
|
54
|
-
- [D7] For standalone `batch` runs, prefer `batch/batch-runner.sh` instead of hand-rolling the loop. It delegates to `@
|
|
54
|
+
- [D7] For standalone `batch` runs, prefer `batch/batch-runner.sh` instead of hand-rolling the loop. It delegates to `@agent-pattern-labs/iso-orchestrator`, persists workflow records in `.jobforge-runs/`, caps bundle fan-out, and mutexes state/report-number writes. Use `JOBFORGE_LEGACY_BATCH_RUNNER=1` only as a fallback.
|
|
55
55
|
why: the old Bash loop encoded resumability and parallelism manually; the iso-orchestrator path makes the durable control state inspectable and prevents report-number collisions under parallel bundles
|
|
56
56
|
|
|
57
57
|
- [D8] Use deterministic local helpers instead of prose when they can answer or validate state, identity, policy, scoring, timing, dispatch, priority, lineage, migration, or safe-export questions. Read `modes/reference-local-helpers.md` when choosing a helper or changing helper wiring.
|
package/CLAUDE.md
CHANGED
|
@@ -51,7 +51,7 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
|
|
|
51
51
|
- [D6] Pick the mode from the **Routing** table below AND name it explicitly in your first response (e.g., "running auto-pipeline mode", "this is a `compare` request"). If no row matches the user's intent, ask which mode fits; do not guess.
|
|
52
52
|
why: silent mode picks mis-route work (a "negotiation" question answered in `offer` mode produces the wrong report shape); naming the mode out loud makes the routing decision reviewable and gives downstream dispatches a reliable anchor
|
|
53
53
|
|
|
54
|
-
- [D7] For standalone `batch` runs, prefer `batch/batch-runner.sh` instead of hand-rolling the loop. It delegates to `@
|
|
54
|
+
- [D7] For standalone `batch` runs, prefer `batch/batch-runner.sh` instead of hand-rolling the loop. It delegates to `@agent-pattern-labs/iso-orchestrator`, persists workflow records in `.jobforge-runs/`, caps bundle fan-out, and mutexes state/report-number writes. Use `JOBFORGE_LEGACY_BATCH_RUNNER=1` only as a fallback.
|
|
55
55
|
why: the old Bash loop encoded resumability and parallelism manually; the iso-orchestrator path makes the durable control state inspectable and prevents report-number collisions under parallel bundles
|
|
56
56
|
|
|
57
57
|
- [D8] Use deterministic local helpers instead of prose when they can answer or validate state, identity, policy, scoring, timing, dispatch, priority, lineage, migration, or safe-export questions. Read `modes/reference-local-helpers.md` when choosing a helper or changing helper wiring.
|
package/README.md
CHANGED
|
@@ -1,242 +1,194 @@
|
|
|
1
1
|
# JobForge
|
|
2
2
|
|
|
3
|
-
> AI-powered job search pipeline
|
|
3
|
+
> AI-powered job search pipeline for opencode: evaluate roles, generate tailored CV PDFs, scan portals, apply to good-fit jobs, and track the whole search locally.
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|

|
|
7
7
|

|
|
8
8
|

|
|
9
|
-

|
|
10
9
|
|
|
11
10
|
<p align="center">
|
|
12
|
-
<img src="demo/demo.gif" alt="JobForge
|
|
11
|
+
<img src="demo/demo.gif" alt="JobForge demo" width="800">
|
|
13
12
|
</p>
|
|
14
13
|
|
|
15
|
-
<p align="center"><em>Paste a job URL. Get a scored evaluation, tailored CV, and
|
|
14
|
+
<p align="center"><em>Paste a job URL. Get a scored evaluation, tailored CV, and tracker entry.</em></p>
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
## Start Here
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
Most users should scaffold a personal job-search project instead of cloning this harness repo directly.
|
|
19
|
+
|
|
20
|
+
### Prerequisites
|
|
21
|
+
|
|
22
|
+
- [opencode](https://opencode.ai) installed and configured
|
|
23
|
+
- Node.js 20.6 or newer
|
|
24
|
+
- Optional: Go, only if you want to build the dashboard TUI
|
|
25
|
+
|
|
26
|
+
### Create Your Project
|
|
20
27
|
|
|
21
28
|
```bash
|
|
22
29
|
npx --package=job-forge create-job-forge my-job-search
|
|
23
30
|
cd my-job-search
|
|
24
31
|
npm install
|
|
25
|
-
opencode
|
|
26
32
|
```
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
Then edit the three personal files the scaffolder creates:
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
| File | What to put there |
|
|
37
|
+
|------|-------------------|
|
|
38
|
+
| `cv.md` | Your CV in markdown. This is the source for matching and PDF generation. |
|
|
39
|
+
| `config/profile.yml` | Your identity, target roles, location constraints, compensation, and proof points. |
|
|
40
|
+
| `portals.yml` | Companies, search queries, and title filters for portal scanning. |
|
|
33
41
|
|
|
34
|
-
|
|
42
|
+
Optional: add `article-digest.md` with portfolio links, case studies, or extra proof points.
|
|
35
43
|
|
|
36
|
-
|
|
44
|
+
### First Run
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Full setup guide and alternative install paths (including contributing to the harness itself): **[docs/SETUP.md](docs/SETUP.md)**.
|
|
46
|
+
```bash
|
|
47
|
+
npx job-forge sync-check
|
|
48
|
+
opencode
|
|
49
|
+
```
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
Inside opencode, paste a job URL or job description. JobForge routes it through the auto-pipeline: evaluation, score, tailored report, PDF, and tracker update.
|
|
45
52
|
|
|
46
|
-
|
|
53
|
+
To see the command menu:
|
|
47
54
|
|
|
48
|
-
|
|
55
|
+
```text
|
|
56
|
+
/job-forge
|
|
57
|
+
```
|
|
49
58
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
59
|
+
## What It Does
|
|
60
|
+
|
|
61
|
+
JobForge is built for selective, high-fit applications. It is not intended for spray-and-pray submission.
|
|
62
|
+
|
|
63
|
+
- Scores opportunities with a consistent weighted rubric.
|
|
64
|
+
- Generates tailored ATS-friendly CV PDFs.
|
|
65
|
+
- Scans configured company portals and job boards.
|
|
66
|
+
- Tracks applications, follow-ups, rejections, offers, reports, and PDFs.
|
|
67
|
+
- Supports batch evaluation and application work through bounded subagents.
|
|
68
|
+
- Uses local helper CLIs for dedupe, scoring, lineage, preflight, postflight, and tracker integrity.
|
|
69
|
+
|
|
70
|
+
## Common Commands
|
|
71
|
+
|
|
72
|
+
Run these from your personal project root after `npm install`.
|
|
73
|
+
|
|
74
|
+
| Need | Command |
|
|
75
|
+
|------|---------|
|
|
76
|
+
| Verify setup after editing profile and CV | `npx job-forge sync-check` |
|
|
77
|
+
| Check tracker and pipeline health | `npx job-forge verify` |
|
|
78
|
+
| Merge batch tracker additions | `npx job-forge merge` |
|
|
79
|
+
| Generate a CV PDF from the current project | `npx job-forge pdf` |
|
|
80
|
+
| Show token usage | `npx job-forge tokens --days 1` |
|
|
81
|
+
| Rebuild harness symlinks | `npx job-forge sync` |
|
|
82
|
+
| Upgrade the harness | `npm run update-harness` |
|
|
83
|
+
|
|
84
|
+
Useful opencode commands:
|
|
85
|
+
|
|
86
|
+
| Need | Command |
|
|
87
|
+
|------|---------|
|
|
88
|
+
| Evaluate a pasted URL or JD | Paste it directly, or use `/job-forge` |
|
|
89
|
+
| Scan configured portals | `/job-forge scan` |
|
|
90
|
+
| Process queued URLs | `/job-forge pipeline` |
|
|
91
|
+
| Batch evaluate roles | `/job-forge batch` |
|
|
92
|
+
| Fill an application form | `/job-forge apply` |
|
|
93
|
+
| Check application status | `/job-forge tracker` |
|
|
94
|
+
| Check due follow-ups | `/job-forge followup` |
|
|
95
|
+
| Draft LinkedIn outreach | `/job-forge contact` |
|
|
96
|
+
| Research a company | `/job-forge deep` |
|
|
97
|
+
| Handle rejection or offer workflows | `/job-forge rejection` or `/job-forge negotiation` |
|
|
98
|
+
|
|
99
|
+
## How The Flow Works
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
Paste a job URL or JD
|
|
103
|
+
|
|
|
104
|
+
v
|
|
105
|
+
Extract role details and classify fit
|
|
106
|
+
|
|
|
107
|
+
v
|
|
108
|
+
Score against profile, CV, location, comp, and role goals
|
|
109
|
+
|
|
|
110
|
+
v
|
|
111
|
+
Create report + tailored PDF + tracker entry
|
|
112
|
+
|
|
|
113
|
+
v
|
|
114
|
+
Apply, follow up, research, or negotiate from the tracked state
|
|
115
|
+
```
|
|
58
116
|
|
|
59
|
-
|
|
117
|
+
## Project Layout
|
|
118
|
+
|
|
119
|
+
A scaffolded personal project looks like this:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
my-job-search/
|
|
123
|
+
├── package.json # depends on job-forge from npm
|
|
124
|
+
├── opencode.json # MCP and opencode configuration
|
|
125
|
+
├── cv.md # personal, gitignored
|
|
126
|
+
├── article-digest.md # optional personal proof points, gitignored
|
|
127
|
+
├── config/profile.yml # personal, gitignored
|
|
128
|
+
├── portals.yml # personal scanner config, gitignored
|
|
129
|
+
├── data/ # pipeline, applications, scan history
|
|
130
|
+
├── reports/ # generated evaluations
|
|
131
|
+
├── output/ # generated PDFs
|
|
132
|
+
├── batch/tracker-additions/ # batch apply/eval results before merge
|
|
133
|
+
├── AGENTS.md # personal overrides
|
|
134
|
+
├── AGENTS.harness.md # symlink into node_modules/job-forge
|
|
135
|
+
├── modes/ # symlinked JobForge modes
|
|
136
|
+
├── templates/ # symlinked policies and templates
|
|
137
|
+
└── node_modules/job-forge/ # the harness package
|
|
138
|
+
```
|
|
60
139
|
|
|
61
|
-
|
|
140
|
+
Your personal files and generated job-search state are gitignored by the scaffolded project.
|
|
62
141
|
|
|
63
|
-
|
|
64
|
-
|---------|-------------|
|
|
65
|
-
| **Auto-Pipeline** | Paste a URL, get a full evaluation + PDF + tracker entry |
|
|
66
|
-
| **Unified Scoring** | 10 weighted dimensions, consistent across all modes, with calibration anchors and deterministic `job-forge score:*` checks |
|
|
67
|
-
| **Anti-AI-Detection CVs** | Writing rules that avoid ATS filters on Indeed, LinkedIn, Workday |
|
|
68
|
-
| **6-Block Evaluation** | Role summary, CV match, level strategy, comp research, personalization, interview prep (STAR+R) |
|
|
69
|
-
| **Interview Story Bank** | Curated bank of 10-12 stories with match counts, archetype tags, and automatic pruning |
|
|
70
|
-
| **Follow-Up System** | `job-forge timeline:*` computes timing-based nudges from local tracker/pipeline sources: Applied 7+ days ago, Contacted 5+ days ago, Interview 1-day thank-you, and 7-day interview nudge. |
|
|
71
|
-
| **Gmail Integration** | MCP server configured to retrieve emails for interview callbacks, offer responses, and application status updates |
|
|
72
|
-
| **Rejection Analysis** | Captures stage + reason, surfaces patterns (archetype gaps, scoring miscalibration) |
|
|
73
|
-
| **Offer Negotiation** | Total comp breakdown, equity valuation, leverage from pipeline, counter-offer scripts |
|
|
74
|
-
| **Deep Research** | Company research that feeds back into scores and interview prep |
|
|
75
|
-
| **Smart LinkedIn Outreach** | Reads evaluation reports to craft targeted messages using top proof points |
|
|
76
|
-
| **Portal Scanner** | 45+ companies pre-configured with fuzzy dedup for reposts |
|
|
77
|
-
| **Batch Processing** | Parallel evaluation with headless AI CLI workers (`opencode run` or `codex exec`), with honest verification flagging |
|
|
78
|
-
| **Durable Batch Orchestration** | `batch-runner.sh` uses `@razroo/iso-orchestrator` for resumable bundle execution, bounded fan-out, mutexed state writes, and workflow records in `.jobforge-runs/`. |
|
|
79
|
-
| **Pipeline Integrity** | Automated merge, dedup, status normalization, health checks |
|
|
80
|
-
| **Cost-Aware Agent Routing** | Three subagents (`@general-free`, `@general-paid`, `@glm-minimal`) with per-task tool surfaces. On OpenCode, JobForge pins all tiers to `opencode-go/deepseek-v4-flash` so application runs avoid overloaded free-model pools. See [Subagent Routing in AGENTS.md](AGENTS.md) for the task-to-agent mapping. |
|
|
81
|
-
| **Trace + Telemetry + Guard + Contract + Score + Canon + Ledger + Capabilities + Context + Cache + Index + Facts + Timeline + Prioritize + Lineage + Preflight + Postflight + Redact + Migrate** | `job-forge trace:*` exposes local harness transcripts, `job-forge telemetry:*` summarizes runs, `job-forge guard:*` audits deterministic policy rules, `templates/contracts.json` enforces artifact shape with `iso-contract`, `job-forge score:*` computes/checks weighted offer scores, `job-forge canon:*` derives stable URL/company/role identity keys, `job-forge ledger:*` queries append-only workflow state, `job-forge capabilities:*` checks role boundaries, `job-forge context:*` plans mode/reference context bundles, `job-forge cache:*` reuses fetched JD/artifact content, `job-forge index:*` queries compact source pointers, `job-forge facts:*` materializes source-backed job/application/candidate facts, `job-forge timeline:*` computes due/overdue follow-up actions, `job-forge prioritize:*` ranks local apply/follow-up candidates, `job-forge lineage:*` detects stale reports/PDFs after source changes, `job-forge preflight:*` plans bounded apply dispatch rounds from file-backed candidate facts, `job-forge postflight:*` settles dispatch outcomes/artifacts/post-steps, `job-forge redact:*` sanitizes local exports, and `job-forge migrate:*` applies safe consumer-project upgrades without MCP/tool-schema overhead. |
|
|
82
|
-
| **Token Cost Visibility** | `job-forge tokens --days 1` for per-session breakdown; `job-forge session-report --since-minutes 60 --log` to flag sessions over budget and append history to `data/token-usage.tsv`. Auto-logged after every batch run. |
|
|
142
|
+
## MCPs And Automation
|
|
83
143
|
|
|
84
|
-
|
|
144
|
+
The scaffolded opencode project wires up the browser and mail automation JobForge needs:
|
|
85
145
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
/job-forge {paste a JD} → Full auto-pipeline (evaluate + PDF + tracker)
|
|
89
|
-
/job-forge scan → Scan portals for new offers
|
|
90
|
-
/job-forge pdf → Generate ATS-optimized CV
|
|
91
|
-
/job-forge batch → Batch evaluate multiple offers
|
|
92
|
-
/job-forge tracker → View application status
|
|
93
|
-
/job-forge apply → Fill application forms with AI
|
|
94
|
-
/job-forge pipeline → Process pending URLs
|
|
95
|
-
/job-forge contact → LinkedIn outreach (uses evaluation report)
|
|
96
|
-
/job-forge deep → Deep company research (feeds back into scores)
|
|
97
|
-
/job-forge followup → Check what needs follow-up action
|
|
98
|
-
/job-forge rejection → Record/analyze rejection patterns
|
|
99
|
-
/job-forge negotiation → Structured offer negotiation
|
|
100
|
-
/job-forge training → Evaluate a course/cert
|
|
101
|
-
/job-forge project → Evaluate a portfolio project
|
|
102
|
-
```
|
|
146
|
+
- Geometra MCP for browser automation and PDF generation.
|
|
147
|
+
- Gmail MCP for recruiter replies, interview callbacks, offer responses, and status emails.
|
|
103
148
|
|
|
104
|
-
|
|
149
|
+
The harness also ships config for Cursor, Claude Code, and Codex through generated symlinks. `npm install` and `npx job-forge sync` refresh those links.
|
|
105
150
|
|
|
106
|
-
|
|
151
|
+
## Contributor Setup
|
|
107
152
|
|
|
108
|
-
|
|
153
|
+
Clone this repo directly only when you want to work on the harness itself: modes, scripts, templates, generated agent configs, or release packaging.
|
|
109
154
|
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
│ Detection │
|
|
117
|
-
└────────┬─────────┘
|
|
118
|
-
│
|
|
119
|
-
┌────────▼─────────┐
|
|
120
|
-
│ A-F Evaluation │ Match, gaps, comp research, STAR stories
|
|
121
|
-
│ (reads cv.md) │ Unified 10-dimension scoring model + iso-score checks
|
|
122
|
-
└────────┬─────────┘
|
|
123
|
-
│
|
|
124
|
-
┌────┼────┐
|
|
125
|
-
▼ ▼ ▼
|
|
126
|
-
Report PDF Tracker
|
|
127
|
-
.md .pdf .tsv
|
|
128
|
-
│
|
|
129
|
-
┌────┼────┐
|
|
130
|
-
▼ ▼ ▼
|
|
131
|
-
Apply Follow Negotiate
|
|
132
|
-
up (if offer)
|
|
155
|
+
```bash
|
|
156
|
+
git clone https://github.com/Agent-Pattern-Labs/JobForge.git
|
|
157
|
+
cd JobForge
|
|
158
|
+
npm install
|
|
159
|
+
npm run build:config
|
|
160
|
+
npm run verify
|
|
133
161
|
```
|
|
134
162
|
|
|
135
|
-
|
|
163
|
+
The source of truth for generated harness configuration is under `iso/`. Run `npm run build:config` after changing `iso/` files.
|
|
136
164
|
|
|
137
|
-
|
|
165
|
+
## Documentation
|
|
138
166
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
├── config/profile.yml # your identity, target roles (personal)
|
|
147
|
-
├── data/ # applications, pipeline, scan history (personal, gitignored)
|
|
148
|
-
├── .jobforge-ledger/ # append-only local workflow events (personal, gitignored)
|
|
149
|
-
├── .jobforge-cache/ # content-addressed local JD/artifact cache (personal, gitignored)
|
|
150
|
-
├── .jobforge-index.json # deterministic artifact lookup index (generated, gitignored)
|
|
151
|
-
├── .jobforge-facts.json # deterministic fact set with provenance (generated, gitignored)
|
|
152
|
-
├── .jobforge-timeline.json # deterministic follow-up action plan (generated, gitignored)
|
|
153
|
-
├── .jobforge-prioritize.json # deterministic next-action ranking (generated, gitignored)
|
|
154
|
-
├── .jobforge-lineage.json # report/PDF lineage and stale-output checks (generated, gitignored)
|
|
155
|
-
├── .jobforge-redacted/ # sanitized local exports (generated, gitignored)
|
|
156
|
-
├── reports/ # generated evaluation reports (personal, gitignored)
|
|
157
|
-
├── batch/{batch-input,batch-state}.tsv, tracker-additions/, logs/ # personal
|
|
158
|
-
├── .jobforge-runs/ # durable batch workflow records (generated)
|
|
159
|
-
├── AGENTS.md # personal overrides (opencode + codex)
|
|
160
|
-
├── CLAUDE.md # personal overrides (Claude Code), @-imports CLAUDE.harness.md
|
|
161
|
-
│
|
|
162
|
-
│ # ↓ symlinks into node_modules/job-forge/, regenerated by postinstall sync.mjs
|
|
163
|
-
├── AGENTS.harness.md # → harness instructions (loaded via opencode.json)
|
|
164
|
-
├── CLAUDE.harness.md # → harness instructions (imported from personal CLAUDE.md)
|
|
165
|
-
├── .mcp.json # → Claude Code MCP config
|
|
166
|
-
├── .codex/config.toml # → Codex MCP config
|
|
167
|
-
├── .cursor/mcp.json # → Cursor MCP config
|
|
168
|
-
├── .cursor/rules/main.mdc # → Cursor always-apply rule
|
|
169
|
-
├── .opencode/skills/job-forge.md # → skill router
|
|
170
|
-
├── .opencode/agents/ # → @general-free, @general-paid, @glm-minimal
|
|
171
|
-
├── modes/ # → _shared.md + skill modes
|
|
172
|
-
├── templates/ # → states.yml, portals.example.yml, cv-template.html, canon.json, score.json, timeline.json, prioritize.json, capabilities.json, context.json, index.json, facts.json, preflight.json, postflight.json, redact.json, migrations.json
|
|
173
|
-
├── batch/batch-prompt.md # → batch worker prompt
|
|
174
|
-
├── batch/batch-runner.sh # → parallel orchestrator
|
|
175
|
-
│
|
|
176
|
-
└── node_modules/job-forge/ # the harness (from npm: `job-forge@2.x`)
|
|
177
|
-
```
|
|
167
|
+
- [Setup](docs/SETUP.md) - full install paths, personalization, tracker setup, token tracking, troubleshooting.
|
|
168
|
+
- [Architecture](docs/ARCHITECTURE.md) - consumer vs harness split, modes, scripts, batch flow, generated config.
|
|
169
|
+
- [Customization](docs/CUSTOMIZATION.md) - profile, archetypes, scanner keywords, states, templates, local overrides.
|
|
170
|
+
- [Model Routing](docs/MODEL-ROUTING.md) - subagent tiers and how to change model routing.
|
|
171
|
+
- [Examples](examples/README.md) - fictional CVs, sample JD, and sample report.
|
|
172
|
+
- [Batch Runner](batch/README.md) - TSV format, durable batch runner, merge flow.
|
|
173
|
+
- [Contributing](CONTRIBUTING.md) - branch workflow and quality checks.
|
|
178
174
|
|
|
179
|
-
|
|
175
|
+
## Troubleshooting
|
|
180
176
|
|
|
181
|
-
|
|
177
|
+
`sync-check` fails before your CV/profile are complete. That is expected until `cv.md` and `config/profile.yml` are filled in.
|
|
182
178
|
|
|
183
|
-
|
|
184
|
-
JobForge/
|
|
185
|
-
├── iso/ # ← SOURCE OF TRUTH for harness configuration
|
|
186
|
-
│ ├── instructions.md # → AGENTS.md + CLAUDE.md (Claude Code / Codex / Cursor)
|
|
187
|
-
│ ├── mcp.json # → .mcp.json + .cursor/mcp.json + .codex/config.toml + opencode.json
|
|
188
|
-
│ ├── agents/*.md # → .opencode/agents/*.md (general-free, general-paid, glm-minimal)
|
|
189
|
-
│ ├── commands/job-forge.md # → .opencode/skills/job-forge.md
|
|
190
|
-
│ └── config.json # per-harness top-level extras (e.g. opencode `instructions` array)
|
|
191
|
-
│
|
|
192
|
-
├── package.json # bin: job-forge, create-job-forge; prepack runs iso-harness
|
|
193
|
-
├── bin/
|
|
194
|
-
│ ├── job-forge.mjs # CLI dispatcher (merge/verify/pdf/tokens/sync/...)
|
|
195
|
-
│ ├── sync.mjs # postinstall: creates symlinks in consumer project
|
|
196
|
-
│ └── create-job-forge.mjs # scaffolder
|
|
197
|
-
├── modes/ # _shared.md + 16 skill modes
|
|
198
|
-
├── templates/ # cv-template.html, portals.example.yml, states.yml, canon.json, score.json, timeline.json, prioritize.json, capabilities.json, context.json, facts.json, preflight.json, postflight.json, redact.json, migrations.json
|
|
199
|
-
├── config/profile.example.yml # template for consumer's profile.yml
|
|
200
|
-
├── batch/{batch-prompt.md,batch-runner.sh} # batch orchestrator
|
|
201
|
-
├── scripts/
|
|
202
|
-
│ ├── batch-orchestrator.mjs # iso-orchestrator-backed batch control loop
|
|
203
|
-
│ ├── tracker-line.mjs # iso-contract-backed tracker TSV renderer
|
|
204
|
-
│ ├── ledger.mjs # iso-ledger-backed workflow-state CLI
|
|
205
|
-
│ ├── capabilities.mjs # iso-capabilities-backed role policy CLI
|
|
206
|
-
│ ├── context.mjs # iso-context-backed context bundle CLI
|
|
207
|
-
│ ├── cache.mjs # iso-cache-backed local artifact cache CLI
|
|
208
|
-
│ ├── index.mjs # iso-index-backed artifact lookup CLI
|
|
209
|
-
│ ├── facts.mjs # iso-facts-backed local fact materialization
|
|
210
|
-
│ ├── timeline.mjs # iso-timeline-backed follow-up planning CLI
|
|
211
|
-
│ ├── prioritize.mjs # iso-prioritize-backed next-action ranking
|
|
212
|
-
│ ├── lineage.mjs # iso-lineage-backed stale artifact checks
|
|
213
|
-
│ ├── score.mjs # iso-score-backed offer scoring CLI
|
|
214
|
-
│ ├── canon.mjs # iso-canon-backed identity normalization CLI
|
|
215
|
-
│ ├── preflight.mjs # iso-preflight-backed dispatch planning CLI
|
|
216
|
-
│ ├── postflight.mjs # iso-postflight-backed dispatch settlement CLI
|
|
217
|
-
│ ├── redact.mjs # iso-redact-backed safe-export redaction CLI
|
|
218
|
-
│ ├── migrate.mjs # iso-migrate-backed consumer-project migrations
|
|
219
|
-
│ ├── token-usage-report.mjs # opencode cost analyzer
|
|
220
|
-
│ └── release/check-source.mjs # version gate for npm publish
|
|
221
|
-
├── tracker-lib.mjs / merge-tracker.mjs / dedup-tracker.mjs / verify-pipeline.mjs
|
|
222
|
-
├── normalize-statuses.mjs / generate-pdf.mjs / cv-sync-check.mjs
|
|
223
|
-
├── dashboard/ # optional Go TUI
|
|
224
|
-
├── fonts/ # Space Grotesk + DM Sans (for PDF)
|
|
225
|
-
├── docs/ # architecture, setup, customization
|
|
226
|
-
└── .github/workflows/ # quality.yml + release.yml (CI publish to npm)
|
|
227
|
-
```
|
|
179
|
+
If symlinks look stale after moving a project, run:
|
|
228
180
|
|
|
229
|
-
|
|
181
|
+
```bash
|
|
182
|
+
npx job-forge sync
|
|
183
|
+
```
|
|
230
184
|
|
|
231
|
-
|
|
185
|
+
If PDF or browser automation fails, start with:
|
|
232
186
|
|
|
233
|
-
|
|
187
|
+
```bash
|
|
188
|
+
opencode mcp list
|
|
189
|
+
```
|
|
234
190
|
|
|
235
|
-
|
|
236
|
-
- [Architecture](docs/ARCHITECTURE.md) — package architecture, modes, evaluation flow, batch runner, pipeline scripts
|
|
237
|
-
- [Customization](docs/CUSTOMIZATION.md) — archetypes, scanner keywords, CV template, states, customizing symlinked modes
|
|
238
|
-
- [Model Routing](docs/MODEL-ROUTING.md) — the three cost-tiered subagents, why the architecture exists, and how to swap models or add your own
|
|
239
|
-
- [Contributing](CONTRIBUTING.md) — branch workflow, quality gate, and ideas for PRs
|
|
191
|
+
Then see [docs/SETUP.md](docs/SETUP.md#troubleshooting) for Geometra, Gmail, dashboard, tracker, and merge troubleshooting.
|
|
240
192
|
|
|
241
193
|
## License
|
|
242
194
|
|
package/batch/README.md
CHANGED
|
@@ -14,7 +14,7 @@ The `batch/` folder holds the **parallel batch runner** for processing 10+ job U
|
|
|
14
14
|
|
|
15
15
|
Per [`.gitignore`](../.gitignore): `batch-input.tsv`, `batch-state.tsv`, `logs/*`, `tracker-additions/*.tsv`, and `.jobforge-runs/`. Empty dirs (`logs/`, `tracker-additions/`) use `.gitkeep` so the tree exists in a fresh clone.
|
|
16
16
|
|
|
17
|
-
The default runner uses `@
|
|
17
|
+
The default runner uses `@agent-pattern-labs/iso-orchestrator` through
|
|
18
18
|
`scripts/batch-orchestrator.mjs`. It persists bundle steps and events in
|
|
19
19
|
`.jobforge-runs/`, caps worker fan-out with `workflow.forEach`, serializes
|
|
20
20
|
state/report-number writes while parallel bundles run, and records worker
|
package/bin/create-job-forge.mjs
CHANGED
|
@@ -240,7 +240,11 @@ const opencodeCfg = {
|
|
|
240
240
|
mcp: {
|
|
241
241
|
geometra: {
|
|
242
242
|
type: 'local',
|
|
243
|
-
command: ['npx', '-
|
|
243
|
+
command: ['npx', '--no-install', 'job-forge', 'mcp:geometra'],
|
|
244
|
+
environment: {
|
|
245
|
+
GEOMETRA_STEALTH: '1',
|
|
246
|
+
GEOMETRA_BROWSER: 'stealth',
|
|
247
|
+
},
|
|
244
248
|
enabled: true,
|
|
245
249
|
},
|
|
246
250
|
gmail: {
|
|
@@ -286,7 +290,7 @@ write('opencode.json', JSON.stringify(opencodeCfg, null, 2) + '\n');
|
|
|
286
290
|
|
|
287
291
|
write('AGENTS.md', `# AGENTS — ${name}
|
|
288
292
|
|
|
289
|
-
Personal job search project using the [job-forge](https://github.com/
|
|
293
|
+
Personal job search project using the [job-forge](https://github.com/Agent-Pattern-Labs/JobForge) harness. The harness lives in \`node_modules/job-forge/\`; most files you need are accessible through symlinks at the project root.
|
|
290
294
|
|
|
291
295
|
**How context loads in this project:** opencode auto-loads *this* file as the project-root AGENTS.md, then loads \`AGENTS.harness.md\` plus \`.opencode/instructions.md\` via \`opencode.json:instructions\`. \`AGENTS.harness.md\` is the shared cross-harness contract; \`.opencode/instructions.md\` is reserved for OpenCode-only addenda. Keep *this* file for personal overrides — anything you want to diverge from or add on top.
|
|
292
296
|
|
|
@@ -442,7 +446,7 @@ node_modules/
|
|
|
442
446
|
|
|
443
447
|
write('README.md', `# ${name}
|
|
444
448
|
|
|
445
|
-
Personal job search project using the [job-forge](https://github.com/
|
|
449
|
+
Personal job search project using the [job-forge](https://github.com/Agent-Pattern-Labs/JobForge) harness.
|
|
446
450
|
|
|
447
451
|
## Setup
|
|
448
452
|
|
|
@@ -459,7 +463,7 @@ Then fill in:
|
|
|
459
463
|
## Updating the harness
|
|
460
464
|
|
|
461
465
|
\`\`\`bash
|
|
462
|
-
npm update job-forge # pulls the latest from
|
|
466
|
+
npm update job-forge # pulls the latest from Agent-Pattern-Labs/JobForge
|
|
463
467
|
job-forge sync # re-run if symlinks drift
|
|
464
468
|
\`\`\`
|
|
465
469
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { dirname, resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const DEFAULT_FALLBACK_PACKAGE = '@geometra/mcp@1.61.3';
|
|
9
|
+
const RESOLVE_ONLY_FLAG = '--job-forge-resolve-target';
|
|
10
|
+
|
|
11
|
+
function normalizeEnv(value) {
|
|
12
|
+
if (typeof value !== 'string') return null;
|
|
13
|
+
const trimmed = value.trim();
|
|
14
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function resolveExplicitPath(rawPath) {
|
|
18
|
+
const resolvedPath = resolve(rawPath);
|
|
19
|
+
if (!existsSync(resolvedPath)) {
|
|
20
|
+
throw new Error(`JOB_FORGE_GEOMETRA_MCP_PATH points to a missing file: ${resolvedPath}`);
|
|
21
|
+
}
|
|
22
|
+
return resolvedPath;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function resolveGeometraMcpLaunchTarget() {
|
|
26
|
+
const explicitPath = normalizeEnv(process.env.JOB_FORGE_GEOMETRA_MCP_PATH);
|
|
27
|
+
if (explicitPath) {
|
|
28
|
+
const resolvedPath = resolveExplicitPath(explicitPath);
|
|
29
|
+
return {
|
|
30
|
+
source: 'env-path',
|
|
31
|
+
command: process.execPath,
|
|
32
|
+
args: [resolvedPath],
|
|
33
|
+
resolvedPath,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
38
|
+
const siblingRepoPath = resolve(scriptDir, '../../geometra/mcp/dist/index.js');
|
|
39
|
+
if (existsSync(siblingRepoPath)) {
|
|
40
|
+
return {
|
|
41
|
+
source: 'sibling-repo',
|
|
42
|
+
command: process.execPath,
|
|
43
|
+
args: [siblingRepoPath],
|
|
44
|
+
resolvedPath: siblingRepoPath,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const packageSpec = normalizeEnv(process.env.JOB_FORGE_GEOMETRA_MCP_PACKAGE) ?? DEFAULT_FALLBACK_PACKAGE;
|
|
49
|
+
return {
|
|
50
|
+
source: 'npm-package',
|
|
51
|
+
command: 'npx',
|
|
52
|
+
args: ['-y', packageSpec],
|
|
53
|
+
packageSpec,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function main(argv = process.argv.slice(2)) {
|
|
58
|
+
const target = resolveGeometraMcpLaunchTarget();
|
|
59
|
+
|
|
60
|
+
if (argv.length === 1 && argv[0] === RESOLVE_ONLY_FLAG) {
|
|
61
|
+
process.stdout.write(`${JSON.stringify(target, null, 2)}\n`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const child = spawn(target.command, [...target.args, ...argv], {
|
|
66
|
+
stdio: 'inherit',
|
|
67
|
+
env: process.env,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
child.on('error', (error) => {
|
|
71
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
72
|
+
process.exit(1);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
child.on('exit', (code, signal) => {
|
|
76
|
+
if (signal) {
|
|
77
|
+
process.kill(process.pid, signal);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
process.exit(code ?? 0);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
|
|
85
|
+
void main();
|
|
86
|
+
}
|