job-forge 2.10.0 → 2.12.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/.cursor/rules/main.mdc +73 -1
- package/AGENTS.md +73 -1
- package/CLAUDE.md +73 -1
- package/config/profile.example.yml +20 -0
- package/iso/instructions.md +73 -1
- package/modes/apply.md +100 -3
- package/package.json +6 -1
package/.cursor/rules/main.mdc
CHANGED
|
@@ -419,6 +419,8 @@ These blocks come from two distinct root causes and require different responses:
|
|
|
419
419
|
|
|
420
420
|
**Rule — do NOT loop retrying a class B block.** One retry with `imeFriendly: true` is the correct test for class A. If the same spam message fires after a clean `imeFriendly` refill, stop, mark Failed, move on. Repeated retries waste subagent time and do not change the outcome.
|
|
421
421
|
|
|
422
|
+
**Class B fix — BYO residential proxy** (added 2026-04-20 via Geometra MCP v1.59.0). When the candidate has configured `proxy:` in `config/profile.yml`, every `geometra_connect` call threads that proxy through to Chromium, which flips the outbound IP from datacenter to residential/mobile and collapses most class-B failures. See the "BYO Residential Proxy" reference section below. Without a configured proxy, class B stays Failed.
|
|
423
|
+
|
|
422
424
|
**Known-block Ashby tenants (2026-04-19 empirical observations).** These tenants fired class B on every attempted submit from a headless datacenter-IP proxy. Orchestrators planning apply dispatches should assume these tenants will Fail in headless — prioritize other portals, or skip same-tenant siblings after a confirmed class B to avoid burning subagent slots:
|
|
423
425
|
|
|
424
426
|
- Vellum, Linear, Vanta, River Financial, Higharc, Trace Labs, Solace Health, Unstructured, ClickUp, Zapier, Deepgram, Ramp, WorkOS, Ashby (self-tenant), Perplexity, **Goody**, **Starbridge**, **Graphite**, **Prompt Health**, **Vantage**
|
|
@@ -510,6 +512,8 @@ geometra_connect({ pageUrl: "https://...", isolated: true, headless: true, slowM
|
|
|
510
512
|
|
|
511
513
|
**Wrong:** running `geometra_connect` without `isolated: true` when submitting multiple forms concurrently. The forms may share state and produce incorrect submissions.
|
|
512
514
|
|
|
515
|
+
**With a configured proxy,** add `proxy: { server, username?, password?, bypass? }` to the same call — see "BYO Residential Proxy" below. The reusable-proxy pool is partitioned by proxy identity, so mixing direct and proxied sessions across parallel rounds is safe.
|
|
516
|
+
|
|
513
517
|
### Session Reuse — When Subagents Cannot Reach Existing Sessions
|
|
514
518
|
|
|
515
519
|
Subagents launched via the `task` tool start with a fresh context and cannot automatically attach to Chromium sessions spawned by a previous orchestrator session. If you dispatch a subagent to fill a form in session `s16`, but `s16` was created by a previous opencode session, the subagent's MCP calls will silently fail (returning empty results) because the subagent's MCP server has no knowledge of `s16`.
|
|
@@ -553,6 +557,17 @@ Step 2: geometra_disconnect({ closeBrowser: true })
|
|
|
553
557
|
Step 3: geometra_connect({ pageUrl: "<the URL the orchestrator gave you>", isolated: true, headless: true, slowMo: 350 })
|
|
554
558
|
```
|
|
555
559
|
|
|
560
|
+
**If the orchestrator passed a `proxy` object in the task prompt** (sourced from `config/profile.yml`), add it to Step 3:
|
|
561
|
+
|
|
562
|
+
```
|
|
563
|
+
Step 3: geometra_connect({
|
|
564
|
+
pageUrl: "<URL>", isolated: true, headless: true, slowMo: 350,
|
|
565
|
+
proxy: { server: "...", username: "...", password: "...", bypass: "..." }
|
|
566
|
+
})
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
Pass the proxy object through unchanged. Do NOT paraphrase or drop fields — `username`/`password`/`bypass` are optional, so only include what the orchestrator gave you. See the "BYO Residential Proxy" reference section for the why.
|
|
570
|
+
|
|
556
571
|
**DO NOT** skip Step 1 or Step 2. **DO NOT** think about whether it's needed. **DO NOT** look at `geometra_list_sessions` output and reason about it — just always call `geometra_disconnect({ closeBrowser: true })` next. The disconnect is a no-op if the pool is empty, and a poison-cure if it isn't.
|
|
557
572
|
|
|
558
573
|
**Single exception:** if the orchestrator's task prompt says literally "attach to sessionId X" or "use existing session X", skip Steps 1-3 and call `geometra_page_model({ sessionId: "X" })` directly.
|
|
@@ -574,7 +589,64 @@ When the orchestrator dispatches an `apply` (form-fill + submit), pick the subag
|
|
|
574
589
|
|
|
575
590
|
---
|
|
576
591
|
|
|
577
|
-
##
|
|
592
|
+
## BYO Residential Proxy — opt-in outbound-IP override
|
|
593
|
+
|
|
594
|
+
**Problem:** on 2026-04-19 cycle 4, 5/5 untested Ashby tenants and 100% of Dropbox-class Cloudflare-fronted portals fingerprint-blocked headless Chromium from datacenter IPs. `imeFriendly: true` fixes class A (React validation lag) but has zero effect on class B (environment fingerprint). There is no in-session software-only fix for class B: the server decided the session is a bot before the form response was rendered.
|
|
595
|
+
|
|
596
|
+
**Fix:** route the spawned Chromium through a residential or mobile proxy the candidate already pays for. Geometra MCP v1.59.0 added a `proxy: { server, username?, password?, bypass? }` parameter on `geometra_connect` and `geometra_prepare_browser` that forwards straight to Playwright's `chromium.launch({ proxy })`. The outbound IP becomes residential/mobile, and the fingerprint check that fired class B no longer trips.
|
|
597
|
+
|
|
598
|
+
**Opt-in, BYO.** JobForge does NOT bundle or resell proxy bandwidth — the candidate brings their own provider (Bright Data, Oxylabs, SOAX, Smartproxy, mobile hotspot, self-hosted SOCKS). Without a configured proxy, JobForge behavior is unchanged from v2.11.0 and earlier.
|
|
599
|
+
|
|
600
|
+
### Where the proxy config lives
|
|
601
|
+
|
|
602
|
+
`config/profile.yml` → top-level `proxy:` block:
|
|
603
|
+
|
|
604
|
+
```yaml
|
|
605
|
+
proxy:
|
|
606
|
+
server: "http://residential.example.com:8080" # http://, https://, or socks5://
|
|
607
|
+
username: "your-proxy-username" # optional
|
|
608
|
+
password: "your-proxy-password" # optional
|
|
609
|
+
bypass: "*.internal,localhost" # optional
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
See `config/profile.example.yml` for the commented-out template.
|
|
613
|
+
|
|
614
|
+
### How the orchestrator threads it through
|
|
615
|
+
|
|
616
|
+
**Orchestrator responsibilities:**
|
|
617
|
+
|
|
618
|
+
1. On session start, read `config/profile.yml` once. If a `proxy:` block is present, capture it as the `PROXY_CONFIG` for the session.
|
|
619
|
+
2. When dispatching any subagent whose work involves a `geometra_connect` call, include `PROXY_CONFIG` verbatim in the task prompt. Example dispatch prompt line: "Pass `proxy: { server: ..., username: ..., password: ..., bypass: ... }` to every `geometra_connect` call you make."
|
|
620
|
+
3. When the orchestrator itself opens a Chromium session (single-application interactive flow), include the same `proxy` object in its own `geometra_connect` call.
|
|
621
|
+
4. If `proxy:` is absent from `profile.yml`, skip the param entirely. Do NOT invent a proxy URL or leave a stale placeholder.
|
|
622
|
+
|
|
623
|
+
**Subagent responsibilities:**
|
|
624
|
+
|
|
625
|
+
1. If the task prompt includes a `proxy` object, pass it through to `geometra_connect` and any `geometra_prepare_browser` calls unchanged.
|
|
626
|
+
2. If the task prompt does NOT include a proxy object, run without one.
|
|
627
|
+
3. Never second-guess the proxy field — if the orchestrator sourced it from `profile.yml`, it's authoritative.
|
|
628
|
+
|
|
629
|
+
### When proxy use is load-bearing
|
|
630
|
+
|
|
631
|
+
Apply these rules when deciding whether the proxy is worth waiting for:
|
|
632
|
+
|
|
633
|
+
- **Required** for known-block Ashby tenants (see the class-B list in the Ashby section above), for `happydance.website` / Cloudflare-fronted ATSes, and for any Lever tenant that previously failed in the class-B pattern.
|
|
634
|
+
- **Recommended** for any Ashby tenant NOT on the class-A-compatible list (base rate prior: ~80-90% block headless).
|
|
635
|
+
- **Optional** for Greenhouse, Workday, Lever-clean tenants — these accept datacenter IPs today; using the proxy adds ~100ms per frame but no material downside.
|
|
636
|
+
- **Not useful** for Typeform (Geometra-unsupported), Avature native-select lag (not a fingerprint issue), JazzHR+reCAPTCHA (reCAPTCHA scores unrelated to IP), Breezy (tenant-configured per-IP throttle — proxy may help or may hit a fresh throttle).
|
|
637
|
+
|
|
638
|
+
### Pool partitioning — why mixed runs are safe
|
|
639
|
+
|
|
640
|
+
The Geometra MCP partitions its reusable-proxy pool by `(server, username, bypass)` — see `@geometra/mcp@1.59.0` release notes. A direct session and a proxied session NEVER share a Chromium instance, and two sessions with different proxy configs don't pool either. Practical consequence: flipping `proxy:` on or off in `profile.yml` mid-session is safe — the next `geometra_connect` just opens a fresh Chromium in its own pool partition.
|
|
641
|
+
|
|
642
|
+
### Troubleshooting
|
|
643
|
+
|
|
644
|
+
| Symptom | Diagnosis |
|
|
645
|
+
|---|---|
|
|
646
|
+
| `Error: Failed to connect to proxy` immediately after `geometra_connect` | Proxy URL is wrong / unreachable. Verify the `server:` field hits the right host:port. |
|
|
647
|
+
| `407 Proxy Authentication Required` | `username` or `password` is wrong or missing. Many residential providers require both. |
|
|
648
|
+
| Class-B submit failure persists even with proxy set | (a) proxy is a datacenter proxy, not residential; (b) same tenant IP-banned your specific proxy's IP pool; (c) tenant uses TLS fingerprint / canvas fingerprint, not IP — switch to a fresh Chromium (isolated: true) and retry once, else mark Failed. |
|
|
649
|
+
| Every `geometra_connect` is 3-5s slower than before | Expected — residential proxies add latency. Trade-off for higher submit-success rate. Do NOT revert unless the acceptance-rate lift is < 5%. |
|
|
578
650
|
|
|
579
651
|
- Node.js (mjs modules), Geometra MCP (PDF + scraping + form filling), Gmail MCP (email), YAML (config), HTML/CSS (template), Markdown (data)
|
|
580
652
|
|
package/AGENTS.md
CHANGED
|
@@ -414,6 +414,8 @@ These blocks come from two distinct root causes and require different responses:
|
|
|
414
414
|
|
|
415
415
|
**Rule — do NOT loop retrying a class B block.** One retry with `imeFriendly: true` is the correct test for class A. If the same spam message fires after a clean `imeFriendly` refill, stop, mark Failed, move on. Repeated retries waste subagent time and do not change the outcome.
|
|
416
416
|
|
|
417
|
+
**Class B fix — BYO residential proxy** (added 2026-04-20 via Geometra MCP v1.59.0). When the candidate has configured `proxy:` in `config/profile.yml`, every `geometra_connect` call threads that proxy through to Chromium, which flips the outbound IP from datacenter to residential/mobile and collapses most class-B failures. See the "BYO Residential Proxy" reference section below. Without a configured proxy, class B stays Failed.
|
|
418
|
+
|
|
417
419
|
**Known-block Ashby tenants (2026-04-19 empirical observations).** These tenants fired class B on every attempted submit from a headless datacenter-IP proxy. Orchestrators planning apply dispatches should assume these tenants will Fail in headless — prioritize other portals, or skip same-tenant siblings after a confirmed class B to avoid burning subagent slots:
|
|
418
420
|
|
|
419
421
|
- Vellum, Linear, Vanta, River Financial, Higharc, Trace Labs, Solace Health, Unstructured, ClickUp, Zapier, Deepgram, Ramp, WorkOS, Ashby (self-tenant), Perplexity, **Goody**, **Starbridge**, **Graphite**, **Prompt Health**, **Vantage**
|
|
@@ -505,6 +507,8 @@ geometra_connect({ pageUrl: "https://...", isolated: true, headless: true, slowM
|
|
|
505
507
|
|
|
506
508
|
**Wrong:** running `geometra_connect` without `isolated: true` when submitting multiple forms concurrently. The forms may share state and produce incorrect submissions.
|
|
507
509
|
|
|
510
|
+
**With a configured proxy,** add `proxy: { server, username?, password?, bypass? }` to the same call — see "BYO Residential Proxy" below. The reusable-proxy pool is partitioned by proxy identity, so mixing direct and proxied sessions across parallel rounds is safe.
|
|
511
|
+
|
|
508
512
|
### Session Reuse — When Subagents Cannot Reach Existing Sessions
|
|
509
513
|
|
|
510
514
|
Subagents launched via the `task` tool start with a fresh context and cannot automatically attach to Chromium sessions spawned by a previous orchestrator session. If you dispatch a subagent to fill a form in session `s16`, but `s16` was created by a previous opencode session, the subagent's MCP calls will silently fail (returning empty results) because the subagent's MCP server has no knowledge of `s16`.
|
|
@@ -548,6 +552,17 @@ Step 2: geometra_disconnect({ closeBrowser: true })
|
|
|
548
552
|
Step 3: geometra_connect({ pageUrl: "<the URL the orchestrator gave you>", isolated: true, headless: true, slowMo: 350 })
|
|
549
553
|
```
|
|
550
554
|
|
|
555
|
+
**If the orchestrator passed a `proxy` object in the task prompt** (sourced from `config/profile.yml`), add it to Step 3:
|
|
556
|
+
|
|
557
|
+
```
|
|
558
|
+
Step 3: geometra_connect({
|
|
559
|
+
pageUrl: "<URL>", isolated: true, headless: true, slowMo: 350,
|
|
560
|
+
proxy: { server: "...", username: "...", password: "...", bypass: "..." }
|
|
561
|
+
})
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
Pass the proxy object through unchanged. Do NOT paraphrase or drop fields — `username`/`password`/`bypass` are optional, so only include what the orchestrator gave you. See the "BYO Residential Proxy" reference section for the why.
|
|
565
|
+
|
|
551
566
|
**DO NOT** skip Step 1 or Step 2. **DO NOT** think about whether it's needed. **DO NOT** look at `geometra_list_sessions` output and reason about it — just always call `geometra_disconnect({ closeBrowser: true })` next. The disconnect is a no-op if the pool is empty, and a poison-cure if it isn't.
|
|
552
567
|
|
|
553
568
|
**Single exception:** if the orchestrator's task prompt says literally "attach to sessionId X" or "use existing session X", skip Steps 1-3 and call `geometra_page_model({ sessionId: "X" })` directly.
|
|
@@ -569,7 +584,64 @@ When the orchestrator dispatches an `apply` (form-fill + submit), pick the subag
|
|
|
569
584
|
|
|
570
585
|
---
|
|
571
586
|
|
|
572
|
-
##
|
|
587
|
+
## BYO Residential Proxy — opt-in outbound-IP override
|
|
588
|
+
|
|
589
|
+
**Problem:** on 2026-04-19 cycle 4, 5/5 untested Ashby tenants and 100% of Dropbox-class Cloudflare-fronted portals fingerprint-blocked headless Chromium from datacenter IPs. `imeFriendly: true` fixes class A (React validation lag) but has zero effect on class B (environment fingerprint). There is no in-session software-only fix for class B: the server decided the session is a bot before the form response was rendered.
|
|
590
|
+
|
|
591
|
+
**Fix:** route the spawned Chromium through a residential or mobile proxy the candidate already pays for. Geometra MCP v1.59.0 added a `proxy: { server, username?, password?, bypass? }` parameter on `geometra_connect` and `geometra_prepare_browser` that forwards straight to Playwright's `chromium.launch({ proxy })`. The outbound IP becomes residential/mobile, and the fingerprint check that fired class B no longer trips.
|
|
592
|
+
|
|
593
|
+
**Opt-in, BYO.** JobForge does NOT bundle or resell proxy bandwidth — the candidate brings their own provider (Bright Data, Oxylabs, SOAX, Smartproxy, mobile hotspot, self-hosted SOCKS). Without a configured proxy, JobForge behavior is unchanged from v2.11.0 and earlier.
|
|
594
|
+
|
|
595
|
+
### Where the proxy config lives
|
|
596
|
+
|
|
597
|
+
`config/profile.yml` → top-level `proxy:` block:
|
|
598
|
+
|
|
599
|
+
```yaml
|
|
600
|
+
proxy:
|
|
601
|
+
server: "http://residential.example.com:8080" # http://, https://, or socks5://
|
|
602
|
+
username: "your-proxy-username" # optional
|
|
603
|
+
password: "your-proxy-password" # optional
|
|
604
|
+
bypass: "*.internal,localhost" # optional
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
See `config/profile.example.yml` for the commented-out template.
|
|
608
|
+
|
|
609
|
+
### How the orchestrator threads it through
|
|
610
|
+
|
|
611
|
+
**Orchestrator responsibilities:**
|
|
612
|
+
|
|
613
|
+
1. On session start, read `config/profile.yml` once. If a `proxy:` block is present, capture it as the `PROXY_CONFIG` for the session.
|
|
614
|
+
2. When dispatching any subagent whose work involves a `geometra_connect` call, include `PROXY_CONFIG` verbatim in the task prompt. Example dispatch prompt line: "Pass `proxy: { server: ..., username: ..., password: ..., bypass: ... }` to every `geometra_connect` call you make."
|
|
615
|
+
3. When the orchestrator itself opens a Chromium session (single-application interactive flow), include the same `proxy` object in its own `geometra_connect` call.
|
|
616
|
+
4. If `proxy:` is absent from `profile.yml`, skip the param entirely. Do NOT invent a proxy URL or leave a stale placeholder.
|
|
617
|
+
|
|
618
|
+
**Subagent responsibilities:**
|
|
619
|
+
|
|
620
|
+
1. If the task prompt includes a `proxy` object, pass it through to `geometra_connect` and any `geometra_prepare_browser` calls unchanged.
|
|
621
|
+
2. If the task prompt does NOT include a proxy object, run without one.
|
|
622
|
+
3. Never second-guess the proxy field — if the orchestrator sourced it from `profile.yml`, it's authoritative.
|
|
623
|
+
|
|
624
|
+
### When proxy use is load-bearing
|
|
625
|
+
|
|
626
|
+
Apply these rules when deciding whether the proxy is worth waiting for:
|
|
627
|
+
|
|
628
|
+
- **Required** for known-block Ashby tenants (see the class-B list in the Ashby section above), for `happydance.website` / Cloudflare-fronted ATSes, and for any Lever tenant that previously failed in the class-B pattern.
|
|
629
|
+
- **Recommended** for any Ashby tenant NOT on the class-A-compatible list (base rate prior: ~80-90% block headless).
|
|
630
|
+
- **Optional** for Greenhouse, Workday, Lever-clean tenants — these accept datacenter IPs today; using the proxy adds ~100ms per frame but no material downside.
|
|
631
|
+
- **Not useful** for Typeform (Geometra-unsupported), Avature native-select lag (not a fingerprint issue), JazzHR+reCAPTCHA (reCAPTCHA scores unrelated to IP), Breezy (tenant-configured per-IP throttle — proxy may help or may hit a fresh throttle).
|
|
632
|
+
|
|
633
|
+
### Pool partitioning — why mixed runs are safe
|
|
634
|
+
|
|
635
|
+
The Geometra MCP partitions its reusable-proxy pool by `(server, username, bypass)` — see `@geometra/mcp@1.59.0` release notes. A direct session and a proxied session NEVER share a Chromium instance, and two sessions with different proxy configs don't pool either. Practical consequence: flipping `proxy:` on or off in `profile.yml` mid-session is safe — the next `geometra_connect` just opens a fresh Chromium in its own pool partition.
|
|
636
|
+
|
|
637
|
+
### Troubleshooting
|
|
638
|
+
|
|
639
|
+
| Symptom | Diagnosis |
|
|
640
|
+
|---|---|
|
|
641
|
+
| `Error: Failed to connect to proxy` immediately after `geometra_connect` | Proxy URL is wrong / unreachable. Verify the `server:` field hits the right host:port. |
|
|
642
|
+
| `407 Proxy Authentication Required` | `username` or `password` is wrong or missing. Many residential providers require both. |
|
|
643
|
+
| Class-B submit failure persists even with proxy set | (a) proxy is a datacenter proxy, not residential; (b) same tenant IP-banned your specific proxy's IP pool; (c) tenant uses TLS fingerprint / canvas fingerprint, not IP — switch to a fresh Chromium (isolated: true) and retry once, else mark Failed. |
|
|
644
|
+
| Every `geometra_connect` is 3-5s slower than before | Expected — residential proxies add latency. Trade-off for higher submit-success rate. Do NOT revert unless the acceptance-rate lift is < 5%. |
|
|
573
645
|
|
|
574
646
|
- Node.js (mjs modules), Geometra MCP (PDF + scraping + form filling), Gmail MCP (email), YAML (config), HTML/CSS (template), Markdown (data)
|
|
575
647
|
|
package/CLAUDE.md
CHANGED
|
@@ -414,6 +414,8 @@ These blocks come from two distinct root causes and require different responses:
|
|
|
414
414
|
|
|
415
415
|
**Rule — do NOT loop retrying a class B block.** One retry with `imeFriendly: true` is the correct test for class A. If the same spam message fires after a clean `imeFriendly` refill, stop, mark Failed, move on. Repeated retries waste subagent time and do not change the outcome.
|
|
416
416
|
|
|
417
|
+
**Class B fix — BYO residential proxy** (added 2026-04-20 via Geometra MCP v1.59.0). When the candidate has configured `proxy:` in `config/profile.yml`, every `geometra_connect` call threads that proxy through to Chromium, which flips the outbound IP from datacenter to residential/mobile and collapses most class-B failures. See the "BYO Residential Proxy" reference section below. Without a configured proxy, class B stays Failed.
|
|
418
|
+
|
|
417
419
|
**Known-block Ashby tenants (2026-04-19 empirical observations).** These tenants fired class B on every attempted submit from a headless datacenter-IP proxy. Orchestrators planning apply dispatches should assume these tenants will Fail in headless — prioritize other portals, or skip same-tenant siblings after a confirmed class B to avoid burning subagent slots:
|
|
418
420
|
|
|
419
421
|
- Vellum, Linear, Vanta, River Financial, Higharc, Trace Labs, Solace Health, Unstructured, ClickUp, Zapier, Deepgram, Ramp, WorkOS, Ashby (self-tenant), Perplexity, **Goody**, **Starbridge**, **Graphite**, **Prompt Health**, **Vantage**
|
|
@@ -505,6 +507,8 @@ geometra_connect({ pageUrl: "https://...", isolated: true, headless: true, slowM
|
|
|
505
507
|
|
|
506
508
|
**Wrong:** running `geometra_connect` without `isolated: true` when submitting multiple forms concurrently. The forms may share state and produce incorrect submissions.
|
|
507
509
|
|
|
510
|
+
**With a configured proxy,** add `proxy: { server, username?, password?, bypass? }` to the same call — see "BYO Residential Proxy" below. The reusable-proxy pool is partitioned by proxy identity, so mixing direct and proxied sessions across parallel rounds is safe.
|
|
511
|
+
|
|
508
512
|
### Session Reuse — When Subagents Cannot Reach Existing Sessions
|
|
509
513
|
|
|
510
514
|
Subagents launched via the `task` tool start with a fresh context and cannot automatically attach to Chromium sessions spawned by a previous orchestrator session. If you dispatch a subagent to fill a form in session `s16`, but `s16` was created by a previous opencode session, the subagent's MCP calls will silently fail (returning empty results) because the subagent's MCP server has no knowledge of `s16`.
|
|
@@ -548,6 +552,17 @@ Step 2: geometra_disconnect({ closeBrowser: true })
|
|
|
548
552
|
Step 3: geometra_connect({ pageUrl: "<the URL the orchestrator gave you>", isolated: true, headless: true, slowMo: 350 })
|
|
549
553
|
```
|
|
550
554
|
|
|
555
|
+
**If the orchestrator passed a `proxy` object in the task prompt** (sourced from `config/profile.yml`), add it to Step 3:
|
|
556
|
+
|
|
557
|
+
```
|
|
558
|
+
Step 3: geometra_connect({
|
|
559
|
+
pageUrl: "<URL>", isolated: true, headless: true, slowMo: 350,
|
|
560
|
+
proxy: { server: "...", username: "...", password: "...", bypass: "..." }
|
|
561
|
+
})
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
Pass the proxy object through unchanged. Do NOT paraphrase or drop fields — `username`/`password`/`bypass` are optional, so only include what the orchestrator gave you. See the "BYO Residential Proxy" reference section for the why.
|
|
565
|
+
|
|
551
566
|
**DO NOT** skip Step 1 or Step 2. **DO NOT** think about whether it's needed. **DO NOT** look at `geometra_list_sessions` output and reason about it — just always call `geometra_disconnect({ closeBrowser: true })` next. The disconnect is a no-op if the pool is empty, and a poison-cure if it isn't.
|
|
552
567
|
|
|
553
568
|
**Single exception:** if the orchestrator's task prompt says literally "attach to sessionId X" or "use existing session X", skip Steps 1-3 and call `geometra_page_model({ sessionId: "X" })` directly.
|
|
@@ -569,7 +584,64 @@ When the orchestrator dispatches an `apply` (form-fill + submit), pick the subag
|
|
|
569
584
|
|
|
570
585
|
---
|
|
571
586
|
|
|
572
|
-
##
|
|
587
|
+
## BYO Residential Proxy — opt-in outbound-IP override
|
|
588
|
+
|
|
589
|
+
**Problem:** on 2026-04-19 cycle 4, 5/5 untested Ashby tenants and 100% of Dropbox-class Cloudflare-fronted portals fingerprint-blocked headless Chromium from datacenter IPs. `imeFriendly: true` fixes class A (React validation lag) but has zero effect on class B (environment fingerprint). There is no in-session software-only fix for class B: the server decided the session is a bot before the form response was rendered.
|
|
590
|
+
|
|
591
|
+
**Fix:** route the spawned Chromium through a residential or mobile proxy the candidate already pays for. Geometra MCP v1.59.0 added a `proxy: { server, username?, password?, bypass? }` parameter on `geometra_connect` and `geometra_prepare_browser` that forwards straight to Playwright's `chromium.launch({ proxy })`. The outbound IP becomes residential/mobile, and the fingerprint check that fired class B no longer trips.
|
|
592
|
+
|
|
593
|
+
**Opt-in, BYO.** JobForge does NOT bundle or resell proxy bandwidth — the candidate brings their own provider (Bright Data, Oxylabs, SOAX, Smartproxy, mobile hotspot, self-hosted SOCKS). Without a configured proxy, JobForge behavior is unchanged from v2.11.0 and earlier.
|
|
594
|
+
|
|
595
|
+
### Where the proxy config lives
|
|
596
|
+
|
|
597
|
+
`config/profile.yml` → top-level `proxy:` block:
|
|
598
|
+
|
|
599
|
+
```yaml
|
|
600
|
+
proxy:
|
|
601
|
+
server: "http://residential.example.com:8080" # http://, https://, or socks5://
|
|
602
|
+
username: "your-proxy-username" # optional
|
|
603
|
+
password: "your-proxy-password" # optional
|
|
604
|
+
bypass: "*.internal,localhost" # optional
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
See `config/profile.example.yml` for the commented-out template.
|
|
608
|
+
|
|
609
|
+
### How the orchestrator threads it through
|
|
610
|
+
|
|
611
|
+
**Orchestrator responsibilities:**
|
|
612
|
+
|
|
613
|
+
1. On session start, read `config/profile.yml` once. If a `proxy:` block is present, capture it as the `PROXY_CONFIG` for the session.
|
|
614
|
+
2. When dispatching any subagent whose work involves a `geometra_connect` call, include `PROXY_CONFIG` verbatim in the task prompt. Example dispatch prompt line: "Pass `proxy: { server: ..., username: ..., password: ..., bypass: ... }` to every `geometra_connect` call you make."
|
|
615
|
+
3. When the orchestrator itself opens a Chromium session (single-application interactive flow), include the same `proxy` object in its own `geometra_connect` call.
|
|
616
|
+
4. If `proxy:` is absent from `profile.yml`, skip the param entirely. Do NOT invent a proxy URL or leave a stale placeholder.
|
|
617
|
+
|
|
618
|
+
**Subagent responsibilities:**
|
|
619
|
+
|
|
620
|
+
1. If the task prompt includes a `proxy` object, pass it through to `geometra_connect` and any `geometra_prepare_browser` calls unchanged.
|
|
621
|
+
2. If the task prompt does NOT include a proxy object, run without one.
|
|
622
|
+
3. Never second-guess the proxy field — if the orchestrator sourced it from `profile.yml`, it's authoritative.
|
|
623
|
+
|
|
624
|
+
### When proxy use is load-bearing
|
|
625
|
+
|
|
626
|
+
Apply these rules when deciding whether the proxy is worth waiting for:
|
|
627
|
+
|
|
628
|
+
- **Required** for known-block Ashby tenants (see the class-B list in the Ashby section above), for `happydance.website` / Cloudflare-fronted ATSes, and for any Lever tenant that previously failed in the class-B pattern.
|
|
629
|
+
- **Recommended** for any Ashby tenant NOT on the class-A-compatible list (base rate prior: ~80-90% block headless).
|
|
630
|
+
- **Optional** for Greenhouse, Workday, Lever-clean tenants — these accept datacenter IPs today; using the proxy adds ~100ms per frame but no material downside.
|
|
631
|
+
- **Not useful** for Typeform (Geometra-unsupported), Avature native-select lag (not a fingerprint issue), JazzHR+reCAPTCHA (reCAPTCHA scores unrelated to IP), Breezy (tenant-configured per-IP throttle — proxy may help or may hit a fresh throttle).
|
|
632
|
+
|
|
633
|
+
### Pool partitioning — why mixed runs are safe
|
|
634
|
+
|
|
635
|
+
The Geometra MCP partitions its reusable-proxy pool by `(server, username, bypass)` — see `@geometra/mcp@1.59.0` release notes. A direct session and a proxied session NEVER share a Chromium instance, and two sessions with different proxy configs don't pool either. Practical consequence: flipping `proxy:` on or off in `profile.yml` mid-session is safe — the next `geometra_connect` just opens a fresh Chromium in its own pool partition.
|
|
636
|
+
|
|
637
|
+
### Troubleshooting
|
|
638
|
+
|
|
639
|
+
| Symptom | Diagnosis |
|
|
640
|
+
|---|---|
|
|
641
|
+
| `Error: Failed to connect to proxy` immediately after `geometra_connect` | Proxy URL is wrong / unreachable. Verify the `server:` field hits the right host:port. |
|
|
642
|
+
| `407 Proxy Authentication Required` | `username` or `password` is wrong or missing. Many residential providers require both. |
|
|
643
|
+
| Class-B submit failure persists even with proxy set | (a) proxy is a datacenter proxy, not residential; (b) same tenant IP-banned your specific proxy's IP pool; (c) tenant uses TLS fingerprint / canvas fingerprint, not IP — switch to a fresh Chromium (isolated: true) and retry once, else mark Failed. |
|
|
644
|
+
| Every `geometra_connect` is 3-5s slower than before | Expected — residential proxies add latency. Trade-off for higher submit-success rate. Do NOT revert unless the acceptance-rate lift is < 5%. |
|
|
573
645
|
|
|
574
646
|
- Node.js (mjs modules), Geometra MCP (PDF + scraping + form filling), Gmail MCP (email), YAML (config), HTML/CSS (template), Markdown (data)
|
|
575
647
|
|
|
@@ -86,3 +86,23 @@ location_constraints:
|
|
|
86
86
|
- US
|
|
87
87
|
requires_visa_sponsorship: false # true → roles in non-authorized countries are blocked unless
|
|
88
88
|
# the JD explicitly mentions visa sponsorship
|
|
89
|
+
|
|
90
|
+
# Optional outbound proxy for the Chromium that Geometra MCP spawns.
|
|
91
|
+
# Uncomment and fill in to route ALL browser traffic through a residential /
|
|
92
|
+
# mobile / SOCKS proxy you already pay for. Bypasses the datacenter-IP
|
|
93
|
+
# fingerprinting that drives ~80-90% of Ashby / Lever / Cloudflare-fronted
|
|
94
|
+
# "flagged as possible spam" submit failures in headless mode.
|
|
95
|
+
#
|
|
96
|
+
# BYO — JobForge does NOT bundle or resell proxy bandwidth. Pick a residential
|
|
97
|
+
# or mobile provider (Bright Data, Oxylabs, SOAX, Smartproxy, etc.), or a
|
|
98
|
+
# mobile hotspot, or your own SOCKS relay. Required: Geometra MCP >= 1.59.0.
|
|
99
|
+
#
|
|
100
|
+
# When present, the apply / scan / auto-pipeline modes thread this into every
|
|
101
|
+
# `geometra_connect` call as `proxy: {...}`. Pool is partitioned by proxy
|
|
102
|
+
# identity so direct and proxied sessions never share a Chromium.
|
|
103
|
+
#
|
|
104
|
+
# proxy:
|
|
105
|
+
# server: "http://residential.example.com:8080" # http://, https://, or socks5://
|
|
106
|
+
# username: "your-proxy-username" # optional; omit if no auth
|
|
107
|
+
# password: "your-proxy-password" # optional; omit if no auth
|
|
108
|
+
# bypass: "*.internal,localhost" # optional comma-separated host patterns
|
package/iso/instructions.md
CHANGED
|
@@ -414,6 +414,8 @@ These blocks come from two distinct root causes and require different responses:
|
|
|
414
414
|
|
|
415
415
|
**Rule — do NOT loop retrying a class B block.** One retry with `imeFriendly: true` is the correct test for class A. If the same spam message fires after a clean `imeFriendly` refill, stop, mark Failed, move on. Repeated retries waste subagent time and do not change the outcome.
|
|
416
416
|
|
|
417
|
+
**Class B fix — BYO residential proxy** (added 2026-04-20 via Geometra MCP v1.59.0). When the candidate has configured `proxy:` in `config/profile.yml`, every `geometra_connect` call threads that proxy through to Chromium, which flips the outbound IP from datacenter to residential/mobile and collapses most class-B failures. See the "BYO Residential Proxy" reference section below. Without a configured proxy, class B stays Failed.
|
|
418
|
+
|
|
417
419
|
**Known-block Ashby tenants (2026-04-19 empirical observations).** These tenants fired class B on every attempted submit from a headless datacenter-IP proxy. Orchestrators planning apply dispatches should assume these tenants will Fail in headless — prioritize other portals, or skip same-tenant siblings after a confirmed class B to avoid burning subagent slots:
|
|
418
420
|
|
|
419
421
|
- Vellum, Linear, Vanta, River Financial, Higharc, Trace Labs, Solace Health, Unstructured, ClickUp, Zapier, Deepgram, Ramp, WorkOS, Ashby (self-tenant), Perplexity, **Goody**, **Starbridge**, **Graphite**, **Prompt Health**, **Vantage**
|
|
@@ -505,6 +507,8 @@ geometra_connect({ pageUrl: "https://...", isolated: true, headless: true, slowM
|
|
|
505
507
|
|
|
506
508
|
**Wrong:** running `geometra_connect` without `isolated: true` when submitting multiple forms concurrently. The forms may share state and produce incorrect submissions.
|
|
507
509
|
|
|
510
|
+
**With a configured proxy,** add `proxy: { server, username?, password?, bypass? }` to the same call — see "BYO Residential Proxy" below. The reusable-proxy pool is partitioned by proxy identity, so mixing direct and proxied sessions across parallel rounds is safe.
|
|
511
|
+
|
|
508
512
|
### Session Reuse — When Subagents Cannot Reach Existing Sessions
|
|
509
513
|
|
|
510
514
|
Subagents launched via the `task` tool start with a fresh context and cannot automatically attach to Chromium sessions spawned by a previous orchestrator session. If you dispatch a subagent to fill a form in session `s16`, but `s16` was created by a previous opencode session, the subagent's MCP calls will silently fail (returning empty results) because the subagent's MCP server has no knowledge of `s16`.
|
|
@@ -548,6 +552,17 @@ Step 2: geometra_disconnect({ closeBrowser: true })
|
|
|
548
552
|
Step 3: geometra_connect({ pageUrl: "<the URL the orchestrator gave you>", isolated: true, headless: true, slowMo: 350 })
|
|
549
553
|
```
|
|
550
554
|
|
|
555
|
+
**If the orchestrator passed a `proxy` object in the task prompt** (sourced from `config/profile.yml`), add it to Step 3:
|
|
556
|
+
|
|
557
|
+
```
|
|
558
|
+
Step 3: geometra_connect({
|
|
559
|
+
pageUrl: "<URL>", isolated: true, headless: true, slowMo: 350,
|
|
560
|
+
proxy: { server: "...", username: "...", password: "...", bypass: "..." }
|
|
561
|
+
})
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
Pass the proxy object through unchanged. Do NOT paraphrase or drop fields — `username`/`password`/`bypass` are optional, so only include what the orchestrator gave you. See the "BYO Residential Proxy" reference section for the why.
|
|
565
|
+
|
|
551
566
|
**DO NOT** skip Step 1 or Step 2. **DO NOT** think about whether it's needed. **DO NOT** look at `geometra_list_sessions` output and reason about it — just always call `geometra_disconnect({ closeBrowser: true })` next. The disconnect is a no-op if the pool is empty, and a poison-cure if it isn't.
|
|
552
567
|
|
|
553
568
|
**Single exception:** if the orchestrator's task prompt says literally "attach to sessionId X" or "use existing session X", skip Steps 1-3 and call `geometra_page_model({ sessionId: "X" })` directly.
|
|
@@ -569,7 +584,64 @@ When the orchestrator dispatches an `apply` (form-fill + submit), pick the subag
|
|
|
569
584
|
|
|
570
585
|
---
|
|
571
586
|
|
|
572
|
-
##
|
|
587
|
+
## BYO Residential Proxy — opt-in outbound-IP override
|
|
588
|
+
|
|
589
|
+
**Problem:** on 2026-04-19 cycle 4, 5/5 untested Ashby tenants and 100% of Dropbox-class Cloudflare-fronted portals fingerprint-blocked headless Chromium from datacenter IPs. `imeFriendly: true` fixes class A (React validation lag) but has zero effect on class B (environment fingerprint). There is no in-session software-only fix for class B: the server decided the session is a bot before the form response was rendered.
|
|
590
|
+
|
|
591
|
+
**Fix:** route the spawned Chromium through a residential or mobile proxy the candidate already pays for. Geometra MCP v1.59.0 added a `proxy: { server, username?, password?, bypass? }` parameter on `geometra_connect` and `geometra_prepare_browser` that forwards straight to Playwright's `chromium.launch({ proxy })`. The outbound IP becomes residential/mobile, and the fingerprint check that fired class B no longer trips.
|
|
592
|
+
|
|
593
|
+
**Opt-in, BYO.** JobForge does NOT bundle or resell proxy bandwidth — the candidate brings their own provider (Bright Data, Oxylabs, SOAX, Smartproxy, mobile hotspot, self-hosted SOCKS). Without a configured proxy, JobForge behavior is unchanged from v2.11.0 and earlier.
|
|
594
|
+
|
|
595
|
+
### Where the proxy config lives
|
|
596
|
+
|
|
597
|
+
`config/profile.yml` → top-level `proxy:` block:
|
|
598
|
+
|
|
599
|
+
```yaml
|
|
600
|
+
proxy:
|
|
601
|
+
server: "http://residential.example.com:8080" # http://, https://, or socks5://
|
|
602
|
+
username: "your-proxy-username" # optional
|
|
603
|
+
password: "your-proxy-password" # optional
|
|
604
|
+
bypass: "*.internal,localhost" # optional
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
See `config/profile.example.yml` for the commented-out template.
|
|
608
|
+
|
|
609
|
+
### How the orchestrator threads it through
|
|
610
|
+
|
|
611
|
+
**Orchestrator responsibilities:**
|
|
612
|
+
|
|
613
|
+
1. On session start, read `config/profile.yml` once. If a `proxy:` block is present, capture it as the `PROXY_CONFIG` for the session.
|
|
614
|
+
2. When dispatching any subagent whose work involves a `geometra_connect` call, include `PROXY_CONFIG` verbatim in the task prompt. Example dispatch prompt line: "Pass `proxy: { server: ..., username: ..., password: ..., bypass: ... }` to every `geometra_connect` call you make."
|
|
615
|
+
3. When the orchestrator itself opens a Chromium session (single-application interactive flow), include the same `proxy` object in its own `geometra_connect` call.
|
|
616
|
+
4. If `proxy:` is absent from `profile.yml`, skip the param entirely. Do NOT invent a proxy URL or leave a stale placeholder.
|
|
617
|
+
|
|
618
|
+
**Subagent responsibilities:**
|
|
619
|
+
|
|
620
|
+
1. If the task prompt includes a `proxy` object, pass it through to `geometra_connect` and any `geometra_prepare_browser` calls unchanged.
|
|
621
|
+
2. If the task prompt does NOT include a proxy object, run without one.
|
|
622
|
+
3. Never second-guess the proxy field — if the orchestrator sourced it from `profile.yml`, it's authoritative.
|
|
623
|
+
|
|
624
|
+
### When proxy use is load-bearing
|
|
625
|
+
|
|
626
|
+
Apply these rules when deciding whether the proxy is worth waiting for:
|
|
627
|
+
|
|
628
|
+
- **Required** for known-block Ashby tenants (see the class-B list in the Ashby section above), for `happydance.website` / Cloudflare-fronted ATSes, and for any Lever tenant that previously failed in the class-B pattern.
|
|
629
|
+
- **Recommended** for any Ashby tenant NOT on the class-A-compatible list (base rate prior: ~80-90% block headless).
|
|
630
|
+
- **Optional** for Greenhouse, Workday, Lever-clean tenants — these accept datacenter IPs today; using the proxy adds ~100ms per frame but no material downside.
|
|
631
|
+
- **Not useful** for Typeform (Geometra-unsupported), Avature native-select lag (not a fingerprint issue), JazzHR+reCAPTCHA (reCAPTCHA scores unrelated to IP), Breezy (tenant-configured per-IP throttle — proxy may help or may hit a fresh throttle).
|
|
632
|
+
|
|
633
|
+
### Pool partitioning — why mixed runs are safe
|
|
634
|
+
|
|
635
|
+
The Geometra MCP partitions its reusable-proxy pool by `(server, username, bypass)` — see `@geometra/mcp@1.59.0` release notes. A direct session and a proxied session NEVER share a Chromium instance, and two sessions with different proxy configs don't pool either. Practical consequence: flipping `proxy:` on or off in `profile.yml` mid-session is safe — the next `geometra_connect` just opens a fresh Chromium in its own pool partition.
|
|
636
|
+
|
|
637
|
+
### Troubleshooting
|
|
638
|
+
|
|
639
|
+
| Symptom | Diagnosis |
|
|
640
|
+
|---|---|
|
|
641
|
+
| `Error: Failed to connect to proxy` immediately after `geometra_connect` | Proxy URL is wrong / unreachable. Verify the `server:` field hits the right host:port. |
|
|
642
|
+
| `407 Proxy Authentication Required` | `username` or `password` is wrong or missing. Many residential providers require both. |
|
|
643
|
+
| Class-B submit failure persists even with proxy set | (a) proxy is a datacenter proxy, not residential; (b) same tenant IP-banned your specific proxy's IP pool; (c) tenant uses TLS fingerprint / canvas fingerprint, not IP — switch to a fresh Chromium (isolated: true) and retry once, else mark Failed. |
|
|
644
|
+
| Every `geometra_connect` is 3-5s slower than before | Expected — residential proxies add latency. Trade-off for higher submit-success rate. Do NOT revert unless the acceptance-rate lift is < 5%. |
|
|
573
645
|
|
|
574
646
|
- Node.js (mjs modules), Geometra MCP (PDF + scraping + form filling), Gmail MCP (email), YAML (config), HTML/CSS (template), Markdown (data)
|
|
575
647
|
|
package/modes/apply.md
CHANGED
|
@@ -1,6 +1,102 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Agent: mode-apply
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Live application assistant. Reads the active application form in Chrome (via Geometra MCP), loads prior context from the offer evaluation, generates personalized answers, and submits the form in one atomic transaction. When the user is applying to more than one job, this mode is invoked by the orchestrator as a dispatched subagent — never driven from an interactive session directly.
|
|
4
|
+
|
|
5
|
+
## Hard limits
|
|
6
|
+
|
|
7
|
+
- [H1] Submit the form in a single `geometra_run_actions` call that chains upload + fill + pick + submit. Never split upload / fill / submit across multiple tool calls.
|
|
8
|
+
why: Greenhouse-style forms regenerate internal field IDs after any DOM-mutating action (especially file uploads); multi-call sequences see stale IDs, enter a retry loop, and burn tens of thousands of tokens (4-retry Anthropic FDE trace, ~10K wasted tokens)
|
|
9
|
+
|
|
10
|
+
- [H2] Never auto-retry a failed submit. On recovery failure, report the error to the orchestrator and stop. The orchestrator decides whether to re-dispatch.
|
|
11
|
+
why: duplicate applications are worse than a missed retry — ATS portals often accept a submit whose response was dropped mid-flight, so a retry double-submits. A human must decide.
|
|
12
|
+
|
|
13
|
+
- [H3] Outcomes MUST be written as TSV to `batch/tracker-additions/{num}-{slug}.tsv` — never append APPLIED / FAILED / SKIP to `data/pipeline.md`.
|
|
14
|
+
why: `pipeline.md` is the URL inbox (`[ ]` → `[x]`); TSVs are the bridge to day files via `npx job-forge merge` (see root `[H6]` in iso/instructions.md)
|
|
15
|
+
|
|
16
|
+
- [H4] Before dispatching the first subagent in a multi-job run, the orchestrator MUST call `geometra_list_sessions` then `geometra_disconnect({closeBrowser: true})`. Every dispatch-round, no exceptions.
|
|
17
|
+
why: prior aborted subagents leave Chromium sessions stuck in the pool; next `geometra_connect` fails with "Not connected" (see root `[H3]`)
|
|
18
|
+
|
|
19
|
+
- [H5] Max 2 parallel `task` dispatches per round. For N jobs, run `ceil(N/2)` sequential rounds of 2. Never emit 3+ dispatches in a single message.
|
|
20
|
+
why: free-tier rate limits + subagent post-cleanup cost; racing more than 2 reliably loses at least one result (see root `[H1]`)
|
|
21
|
+
|
|
22
|
+
## Defaults
|
|
23
|
+
|
|
24
|
+
- [D1] Prefer the structured `location_constraints` block in `config/profile.yml` over the prose `location.*` / `compensation.location_flexibility` fields. Fall back to prose only when `location_constraints` is absent.
|
|
25
|
+
why: structured is O(1) field lookup; prose requires LLM interpretation per dispatch. 2026-04-18 empirical: prose path reached the right call but burned interpretation cycles on every candidate.
|
|
26
|
+
|
|
27
|
+
- [D2] When Geometra MCP is unavailable, ask the candidate to share a screenshot, paste form questions as text, or provide company + role for lookup.
|
|
28
|
+
why: Geometra is the expected primary path; gracefully degrade without refusing to help.
|
|
29
|
+
|
|
30
|
+
- [D3] On a detected role change (role on screen ≠ evaluated role in the report), warn the candidate and ask whether to adapt answers or re-evaluate. Do not silently proceed.
|
|
31
|
+
why: adapting answers to the wrong role produces mis-targeted cover letters and the candidate won't catch it until the recruiter does
|
|
32
|
+
|
|
33
|
+
- [D4] Always pass `imeFriendly: true` on `fill_fields` — safe default everywhere, load-bearing for Ashby.
|
|
34
|
+
why: Ashby's React form swallows programmatic text input silently; `imeFriendly: true` fires composition events that clear React's internal validity state. Zero cost on other portals. Confirmed fix: Supabase #793 (2026-04-19).
|
|
35
|
+
|
|
36
|
+
- [D5] Fetch `geometra_form_schema` at most once per application, right after the initial `geometra_connect`. Operate on labels thereafter.
|
|
37
|
+
why: schema re-fetches return hundreds of nested field IDs and pollute context; labels don't change mid-flow, so the second fetch is just paying for the same payload twice
|
|
38
|
+
|
|
39
|
+
- [D6] Use `fieldLabel` over `fieldId` everywhere it works.
|
|
40
|
+
why: labels are stable across DOM refreshes; IDs are regenerated
|
|
41
|
+
|
|
42
|
+
- [D7] If the orchestrator's task prompt includes a `proxy` object (sourced from `config/profile.yml`), pass it verbatim into every `geometra_connect` call — including Call 3 of the recovery sequence. If absent, run without one; never invent a proxy URL.
|
|
43
|
+
why: class-B Ashby / Cloudflare-fronted portals need a residential outbound IP; the fix is wired in Geometra MCP v1.59.0 but the orchestrator owns the config pipe. See "BYO Residential Proxy" in iso/instructions.md.
|
|
44
|
+
|
|
45
|
+
## Procedure
|
|
46
|
+
|
|
47
|
+
1. `geometra_connect` + `geometra_page_model`; thread `proxy` if present [D7]; no WebFetch [D5].
|
|
48
|
+
2. If Geometra is unavailable, ask for screenshot or pasted text [D2].
|
|
49
|
+
3. Extract company + role; Grep `reports/` for a matching evaluation.
|
|
50
|
+
4. Load full report + Section G if present.
|
|
51
|
+
5. Compare role on screen vs evaluated role [D3].
|
|
52
|
+
6. If different, pause for the candidate's decision [D3].
|
|
53
|
+
7. Before dispatch, run Geometra cleanup [H4] and location filter [D1].
|
|
54
|
+
8. Extract form questions; classify each Section-G vs new.
|
|
55
|
+
9. Generate answers from Block B + Block F + Section G + JD.
|
|
56
|
+
10. Submit as ONE `run_actions` call [H1] using labels [D6] with `imeFriendly: true` [D4].
|
|
57
|
+
11. On session error, run the 4-step recovery; only one retry [H2].
|
|
58
|
+
12. On OTP prompt, fetch the code from Gmail via `gmail_get_message`.
|
|
59
|
+
13. Submit the OTP with `geometra_fill_otp` and click Submit.
|
|
60
|
+
14. Write outcome as `batch/tracker-additions/*.tsv` [H3].
|
|
61
|
+
15. Cap parallelism at 2 per round [H5]; one in-flight per company.
|
|
62
|
+
|
|
63
|
+
## Routing
|
|
64
|
+
|
|
65
|
+
| If the role on screen... | Action |
|
|
66
|
+
|---|---|
|
|
67
|
+
| Matches the evaluated report exactly | Proceed with Section G answers |
|
|
68
|
+
| Is a closely related variant (same archetype) | Warn, offer to adapt [D3] |
|
|
69
|
+
| Is materially different (different archetype) | Warn, offer to re-evaluate [D3] |
|
|
70
|
+
| Has no evaluation report | Offer to run auto-pipeline first |
|
|
71
|
+
| Location conflicts with profile.yml constraints | Mark `Discarded`, do not dispatch [D1] |
|
|
72
|
+
| otherwise | Ask the candidate what they want |
|
|
73
|
+
|
|
74
|
+
## Output format
|
|
75
|
+
|
|
76
|
+
The apply subagent returns a short structured message to the orchestrator (not prose to the user):
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
APPLIED <url> — report #NNN, score X.X/5, tenant <ats>
|
|
80
|
+
tracker TSV: batch/tracker-additions/<num>-<slug>.tsv
|
|
81
|
+
notes: <one-line observation>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or, on failure:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
APPLY FAILED AFTER RECOVERY: <url>
|
|
88
|
+
Error 1: <first error>
|
|
89
|
+
Error 2: <post-recovery error>
|
|
90
|
+
Recommend: re-dispatch on @general-paid
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
# Reference
|
|
96
|
+
|
|
97
|
+
Sections below are the detailed runbooks, decision tables, and portal-specific empirical notes for the rules above. The contract is the `## Hard limits` / `## Defaults` / `## Procedure` / `## Routing` block above; this material is what the subagent consults during execution.
|
|
98
|
+
|
|
99
|
+
## Apply the session-length rule — REQUIRED
|
|
4
100
|
|
|
5
101
|
## Apply the session-length rule — REQUIRED
|
|
6
102
|
|
|
@@ -224,7 +320,8 @@ Call 3: geometra_connect({
|
|
|
224
320
|
pageUrl: "<the same URL as before>",
|
|
225
321
|
isolated: true,
|
|
226
322
|
headless: true,
|
|
227
|
-
slowMo: 350
|
|
323
|
+
slowMo: 350,
|
|
324
|
+
proxy: <pass through from task prompt if present; omit otherwise>
|
|
228
325
|
})
|
|
229
326
|
Call 4: geometra_run_actions({
|
|
230
327
|
sessionId: "<new sessionId from Call 3>",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "job-forge",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "AI-powered job search pipeline built on opencode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,9 +20,14 @@
|
|
|
20
20
|
"tokens:log": "node scripts/token-usage-report.mjs --days 1 --append",
|
|
21
21
|
"trace:list": "iso-trace list --since 7d --cwd .",
|
|
22
22
|
"trace:stats": "iso-trace stats --since 7d --cwd .",
|
|
23
|
+
"trace:show": "iso-trace show",
|
|
24
|
+
"plan": "iso plan .",
|
|
23
25
|
"lint:agentmd": "agentmd lint iso/instructions.md",
|
|
26
|
+
"lint:modes": "isolint lint modes/",
|
|
24
27
|
"test:agentmd": "agentmd test iso/instructions.md --fixtures fixtures/instructions.yml --via claude-code --model claude-haiku-4-5 --concurrency 2",
|
|
25
28
|
"test:agentmd:baseline": "agentmd test iso/instructions.md --fixtures fixtures/instructions.yml --via claude-code --model claude-haiku-4-5 --concurrency 2 --trials 3 --format json --out fixtures/baseline.json",
|
|
29
|
+
"test:agentmd:apply": "agentmd test modes/apply.md --fixtures fixtures/modes/apply.yml --via claude-code --model claude-haiku-4-5 --concurrency 2 --trials 3",
|
|
30
|
+
"lint:agentmd:modes": "agentmd lint modes/apply.md",
|
|
26
31
|
"build:config": "iso build .",
|
|
27
32
|
"prepack": "iso build .",
|
|
28
33
|
"release:check-source": "node ./scripts/release/check-source.mjs",
|