job-forge 2.14.11 → 2.14.13
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/.claude/agents/general-free.md +2 -2
- package/.claude/agents/general-paid.md +5 -5
- package/.claude/agents/glm-minimal.md +1 -1
- package/.cursor/rules/agent-general-free.mdc +2 -2
- package/.cursor/rules/agent-general-paid.mdc +5 -5
- package/.cursor/rules/agent-glm-minimal.mdc +1 -1
- package/.cursor/rules/main.mdc +3 -3
- package/.opencode/agents/general-free.md +3 -8
- package/.opencode/agents/general-paid.md +6 -13
- package/.opencode/agents/glm-minimal.md +2 -7
- package/.opencode/skills/job-forge.md +8 -3
- package/AGENTS.md +3 -3
- package/CLAUDE.md +3 -3
- package/README.md +2 -2
- package/bin/create-job-forge.mjs +10 -48
- package/bin/sync.mjs +0 -1
- package/docs/ARCHITECTURE.md +2 -2
- package/docs/MODEL-ROUTING.md +43 -76
- package/docs/README.md +1 -1
- package/iso/agents/general-free.md +5 -13
- package/iso/agents/general-paid.md +8 -20
- package/iso/agents/glm-minimal.md +4 -11
- package/iso/commands/job-forge.md +8 -3
- package/iso/config.json +1 -42
- package/iso/instructions.md +3 -3
- package/models.yaml +25 -11
- package/modes/apply.md +13 -10
- package/opencode.json +5 -26
- package/package.json +2 -3
- package/scripts/check-iso-smoke.mjs +7 -3
- package/scripts/telemetry.mjs +256 -20
- package/.opencode/opencode-model-fallback.json +0 -22
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Procedural worker on
|
|
2
|
+
description: Procedural worker on the low-cost DeepSeek V4 Flash OpenCode route. Use for form filling via Geometra, tracker updates, TSV merges, scan dedup, OTP retrieval, and other mechanical/scripted tasks where quality-sensitive text generation is NOT required.
|
|
3
3
|
role: fast
|
|
4
4
|
targets:
|
|
5
|
-
# No inline model:
|
|
6
|
-
#
|
|
5
|
+
# No inline model: JobForge's models.yaml maps role "fast" to each
|
|
6
|
+
# harness's cheapest reliable model. On OpenCode that is pinned to
|
|
7
|
+
# opencode-go/deepseek-v4-flash. Claude Code reads
|
|
7
8
|
# .claude/iso-route.resolved.json; OpenCode reads opencode.json's
|
|
8
9
|
# agent.fast.model (iso-harness 0.6.0+).
|
|
9
10
|
opencode:
|
|
10
11
|
mode: subagent
|
|
11
12
|
temperature: 0.1
|
|
12
13
|
reasoningEffort: minimal
|
|
13
|
-
# Primary comes from models.yaml: opencode/big-pickle on OpenCode.
|
|
14
|
-
# Fallback chain stays free-only and intentionally excludes
|
|
15
|
-
# openrouter/minimax/minimax-m2.5:free because recent traces showed
|
|
16
|
-
# repeated read({ path|file_path }) schema drift on that route.
|
|
17
|
-
fallback_models:
|
|
18
|
-
- openrouter/z-ai/glm-4.5-air:free
|
|
19
|
-
- openrouter/openai/gpt-oss-20b:free
|
|
20
|
-
- openrouter/nvidia/nemotron-3-nano-30b-a3b:free
|
|
21
|
-
- openrouter/qwen/qwen3-coder:free
|
|
22
14
|
tools:
|
|
23
15
|
geometra_connect: true
|
|
24
16
|
geometra_page_model: true
|
|
@@ -34,7 +26,7 @@ targets:
|
|
|
34
26
|
task: false
|
|
35
27
|
---
|
|
36
28
|
|
|
37
|
-
You are the @general-free subagent. You run on
|
|
29
|
+
You are the @general-free subagent. You run on JobForge's low-cost procedural model, which means the orchestrator has delegated this task to you **specifically because the work is procedural**: deterministic steps, scripted outputs, no nuanced writing required.
|
|
38
30
|
|
|
39
31
|
## Run This Pre-Flight First Every Time
|
|
40
32
|
|
|
@@ -1,28 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Quality-sensitive worker on the
|
|
2
|
+
description: Quality-sensitive worker on the low-cost DeepSeek V4 Flash OpenCode route by default. Use for offer evaluation narratives (Blocks A-F), cover letter generation, "Why X?" form answers, interview STAR stories, and other tasks where writing quality and judgment matter.
|
|
3
3
|
role: quality
|
|
4
4
|
targets:
|
|
5
|
-
# No inline model: JobForge's models.yaml maps role "quality" to
|
|
6
|
-
#
|
|
7
|
-
# quality-tier defaults from the standard preset. Claude Code reads
|
|
5
|
+
# No inline model: JobForge's models.yaml maps role "quality" to
|
|
6
|
+
# opencode-go/deepseek-v4-flash on OpenCode, while Claude/Codex keep
|
|
7
|
+
# their quality-tier defaults from the standard preset. Claude Code reads
|
|
8
8
|
# .claude/iso-route.resolved.json; OpenCode reads opencode.json's
|
|
9
9
|
# agent.quality.model (iso-harness 0.6.0+).
|
|
10
10
|
opencode:
|
|
11
11
|
mode: subagent
|
|
12
12
|
temperature: 0.3
|
|
13
13
|
reasoningEffort: medium
|
|
14
|
-
# Primary (qwen/qwen3-next-80b-a3b-instruct:free) resolves from the
|
|
15
|
-
# openrouter-free preset. First fallbacks intentionally avoid another
|
|
16
|
-
# immediate hop through the same Venice/Qwen pool when OpenRouter
|
|
17
|
-
# returns "[Venice] insufficient …" — gpt-oss-120b + nemotron are
|
|
18
|
-
# usually different backends. Remaining picks stay free-only.
|
|
19
|
-
fallback_models:
|
|
20
|
-
- openrouter/openai/gpt-oss-120b:free
|
|
21
|
-
- openrouter/nvidia/nemotron-3-super-120b-a12b:free
|
|
22
|
-
- openrouter/z-ai/glm-4.5-air:free
|
|
23
|
-
- openrouter/qwen/qwen3-coder:free
|
|
24
|
-
- openrouter/google/gemma-4-31b-it:free
|
|
25
|
-
- openrouter/meta-llama/llama-3.3-70b-instruct:free
|
|
26
14
|
tools:
|
|
27
15
|
geometra_connect: true
|
|
28
16
|
geometra_page_model: true
|
|
@@ -40,10 +28,10 @@ targets:
|
|
|
40
28
|
|
|
41
29
|
You are the @general-paid subagent. The orchestrator delegated this task to you because it requires quality writing or judgment — the kind of work `@general-free` isn't well-suited for.
|
|
42
30
|
|
|
43
|
-
On OpenCode, this agent
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
were given.
|
|
31
|
+
On OpenCode, this agent defaults to DeepSeek V4 Flash so application work
|
|
32
|
+
does not fall back into overloaded free OpenRouter pools. On other harnesses,
|
|
33
|
+
the same role may still resolve to a premium model. Your job is still the
|
|
34
|
+
same: produce the best final writing you can from the context you were given.
|
|
47
35
|
|
|
48
36
|
## Do These Tasks
|
|
49
37
|
|
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Narrow-scope extractor on
|
|
2
|
+
description: Narrow-scope extractor on the low-cost DeepSeek V4 Flash OpenCode route. Use for single-purpose tasks where the orchestrator passes the exact input and expects a small, structured output — e.g., "extract these 8 fields from this JD text" or "parse this form schema into a label→type map". NOT for multi-step workflows.
|
|
3
3
|
role: minimal
|
|
4
4
|
targets:
|
|
5
|
-
# No inline model:
|
|
6
|
-
#
|
|
5
|
+
# No inline model: JobForge's models.yaml maps role "minimal" to each
|
|
6
|
+
# harness's smallest credible model. On OpenCode that is pinned to
|
|
7
|
+
# opencode-go/deepseek-v4-flash. Claude Code reads
|
|
7
8
|
# .claude/iso-route.resolved.json; OpenCode reads opencode.json's
|
|
8
9
|
# agent.minimal.model (iso-harness 0.6.0+).
|
|
9
10
|
opencode:
|
|
10
11
|
mode: subagent
|
|
11
12
|
temperature: 0
|
|
12
13
|
reasoningEffort: none
|
|
13
|
-
# Primary (openai/gpt-oss-20b:free) resolves from openrouter-free
|
|
14
|
-
# preset. Fallback chain sticks to small dense models with reliable
|
|
15
|
-
# structured-output behavior — no creative generation upstream.
|
|
16
|
-
fallback_models:
|
|
17
|
-
- openrouter/google/gemma-4-26b-a4b-it:free
|
|
18
|
-
- openrouter/nvidia/nemotron-nano-9b-v2:free
|
|
19
|
-
- openrouter/google/gemma-4-31b-it:free
|
|
20
|
-
- openrouter/z-ai/glm-4.5-air:free
|
|
21
14
|
tools:
|
|
22
15
|
geometra_*: false
|
|
23
16
|
gmail_*: false
|
|
@@ -140,13 +140,18 @@ When the user says "apply to N jobs", "process the pipeline", or similar, execut
|
|
|
140
140
|
|
|
141
141
|
```
|
|
142
142
|
Step 1 — Enumerate candidates
|
|
143
|
-
- Grep data/applications
|
|
143
|
+
- Grep data/applications/*.md for status "Evaluated" without loading every file into context
|
|
144
144
|
- Also read data/pipeline.md for unprocessed URLs
|
|
145
145
|
- Build ordered list: candidates = [job_1, job_2, ..., job_N]
|
|
146
146
|
|
|
147
147
|
Step 2 — Dedup against already-applied
|
|
148
|
-
- For each candidate,
|
|
149
|
-
|
|
148
|
+
- For each candidate, grep all four sources for URL and company+role:
|
|
149
|
+
data/pipeline.md, data/applications/*.md, batch/tracker-additions/*.tsv,
|
|
150
|
+
batch/tracker-additions/merged/*.tsv
|
|
151
|
+
- Drop any APPLIED / Applied match before counting toward N. Never re-apply.
|
|
152
|
+
- If a subagent later returns SKIP because it found a duplicate, treat that as
|
|
153
|
+
a missed preflight check; finish the current round, re-run dedupe, then pick
|
|
154
|
+
a replacement from the remaining candidates.
|
|
150
155
|
|
|
151
156
|
Step 3 — Pre-flight cleanup (once, before the loop)
|
|
152
157
|
- geometra_list_sessions()
|
package/iso/config.json
CHANGED
|
@@ -1,49 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"opencodeModelFallback": {
|
|
3
|
-
"cooldown_seconds": 60,
|
|
4
|
-
"timeout_seconds": 30,
|
|
5
|
-
"notify_on_fallback": true,
|
|
6
|
-
"fallback_models": [
|
|
7
|
-
"openrouter/openai/gpt-oss-120b:free",
|
|
8
|
-
"openrouter/z-ai/glm-4.5-air:free",
|
|
9
|
-
"openrouter/nvidia/nemotron-3-super-120b-a12b:free",
|
|
10
|
-
"openrouter/qwen/qwen3-next-80b-a3b-instruct:free"
|
|
11
|
-
],
|
|
12
|
-
"retryable_error_patterns": [
|
|
13
|
-
"\\bvenice\\b",
|
|
14
|
-
"insufficient\\s+usd",
|
|
15
|
-
"insufficient\\s+.*\\s+diem",
|
|
16
|
-
"diem\\s+balance",
|
|
17
|
-
"add\\s+credits",
|
|
18
|
-
"chutes",
|
|
19
|
-
"insufficient\\s+(?:credits?|funds?|balance)",
|
|
20
|
-
"credit.*balance.*too.*low",
|
|
21
|
-
"(?:temporarily\\s+)?unavailable|overloaded|try\\s+again"
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
2
|
"targets": {
|
|
25
3
|
"opencode": {
|
|
26
|
-
"plugin": ["@razroo/opencode-model-fallback"],
|
|
27
4
|
"instructions": ["templates/states.yml"],
|
|
28
|
-
"small_model": "
|
|
29
|
-
"provider": {
|
|
30
|
-
"openrouter": {
|
|
31
|
-
"models": {
|
|
32
|
-
"qwen/qwen3-coder:free": {},
|
|
33
|
-
"z-ai/glm-4.5-air:free": {},
|
|
34
|
-
"qwen/qwen3-next-80b-a3b-instruct:free": {},
|
|
35
|
-
"openai/gpt-oss-20b:free": {},
|
|
36
|
-
"openai/gpt-oss-120b:free": {},
|
|
37
|
-
"minimax/minimax-m2.5:free": {},
|
|
38
|
-
"nvidia/nemotron-3-super-120b-a12b:free": {},
|
|
39
|
-
"nvidia/nemotron-3-nano-30b-a3b:free": {},
|
|
40
|
-
"nvidia/nemotron-nano-9b-v2:free": {},
|
|
41
|
-
"google/gemma-4-26b-a4b-it:free": {},
|
|
42
|
-
"google/gemma-4-31b-it:free": {},
|
|
43
|
-
"meta-llama/llama-3.3-70b-instruct:free": {}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
5
|
+
"small_model": "opencode-go/deepseek-v4-flash"
|
|
47
6
|
}
|
|
48
7
|
}
|
|
49
8
|
}
|
package/iso/instructions.md
CHANGED
|
@@ -5,9 +5,9 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
|
|
|
5
5
|
## Hard limits
|
|
6
6
|
|
|
7
7
|
- [H1] Max 2 parallel `task` dispatches per message. For N jobs, run `ceil(N/2)` sequential rounds of 2. A round is not complete until both subagents return a final outcome (`APPLIED`, `APPLY FAILED`, `SKIP`, `Discarded`, or a written TSV path). A `task` tool result that only gives a session id / title is a launch acknowledgement, not completion. Applies in all modes, for all user phrasings ("urgent", "apply to 10 jobs now").
|
|
8
|
-
why:
|
|
8
|
+
why: each subagent requires post-cleanup and racing more than 2 reliably loses at least one result. On 2026-04-25 the orchestrator launched round 2 while round 1 had only returned task ids, leaving four application subagents in flight and losing two provider recoveries
|
|
9
9
|
|
|
10
|
-
- [H2] Max 1 application per company+role. Before every `apply` dispatch, grep all four sources for the URL and for `company+role`: `data/pipeline.md`, all `data/applications/*.md` day files, `batch/tracker-additions/*.tsv`, `batch/tracker-additions/merged/*.tsv`. If any source shows APPLIED / Applied, skip the dispatch.
|
|
10
|
+
- [H2] Max 1 application per company+role. Before every `apply` dispatch, grep all four sources for the URL and for `company+role`: `data/pipeline.md`, all `data/applications/*.md` day files, `batch/tracker-additions/*.tsv`, `batch/tracker-additions/merged/*.tsv`. If any source shows APPLIED / Applied, skip the dispatch and pick a replacement from the remaining candidate list. Do not count duplicates toward a requested "apply to N jobs" total, and do not delegate obvious duplicates just so a subagent can return SKIP.
|
|
11
11
|
why: 2026-04 same-day batch collision — when two batches target the same role, `npx job-forge merge` updates the existing day-file row rather than appending, so grepping day files alone misses earlier-batch applies; merged/*.tsv is the only place the breadcrumb remains
|
|
12
12
|
|
|
13
13
|
- [H3] Before every batch of `task` dispatches that will use Geometra, call `geometra_list_sessions` then `geometra_disconnect({closeBrowser: true})`. Every round, no exceptions. Name this cleanup as an explicit "step 0" in your first-response plan for any multi-apply request — it is the most frequently skipped guardrail in practice, and skipping it produces cascade "Not connected" failures on the next dispatch.
|
|
@@ -37,7 +37,7 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
|
|
|
37
37
|
why: iso-trace showed 0.25% Agent calls across 5174 turns under a prior over-broad "delegate before 2nd tool call" rule — the rule was ignored in practice; narrowing matches the original cache-bust incident
|
|
38
38
|
|
|
39
39
|
- [D2] Route subagent work by cost tier. `@general-free`: procedural — form-fill, TSV merge, verify, OTP retrieval, portal scan metadata extraction, one-shot structured-field transforms. `@general-paid`: quality-sensitive — offer evaluation narrative Blocks A-F, cover letters, "Why X?" answers, STAR interview stories, LinkedIn outreach. `@glm-minimal`: narrow ≤5K-input one-shot extract/classify jobs that do not need context.
|
|
40
|
-
why:
|
|
40
|
+
why: OpenCode routes all JobForge tiers through DeepSeek V4 Flash by default now; recent traces showed free OpenRouter fallbacks freezing or hitting provider balance errors during applications
|
|
41
41
|
|
|
42
42
|
- [D3] Read the active mode file before dispatch. Mode files own score gates, provider fallback, portal runbooks, and output shape.
|
|
43
43
|
why: mode-specific rules change faster than global orchestration rules; keeping them out of the shared prefix preserves cache efficiency and prevents stale branches
|
package/models.yaml
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
# JobForge model policy.
|
|
2
2
|
#
|
|
3
|
-
# Extends @razroo/iso-route's bundled "
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# node_modules/@razroo/iso-route/presets/openrouter-free.yaml; run
|
|
8
|
-
# `npx iso-route plan models.yaml` to see the resolved policy.
|
|
3
|
+
# Extends @razroo/iso-route's bundled "standard" preset, then pins every
|
|
4
|
+
# OpenCode route to DeepSeek V4 Flash. Recent traces showed free OpenRouter
|
|
5
|
+
# routes freezing or falling through Venice balance errors, so JobForge's
|
|
6
|
+
# OpenCode default is now "best affordable paid" rather than "free".
|
|
9
7
|
#
|
|
10
8
|
# JobForge's subagents bind to preset roles via the `role:` field in
|
|
11
9
|
# iso/agents/<slug>.md:
|
|
12
|
-
# @general-free → role: fast (Haiku /
|
|
13
|
-
# @general-paid → role: quality (Opus 4.7 /
|
|
14
|
-
# @glm-minimal → role: minimal (Haiku /
|
|
10
|
+
# @general-free → role: fast (Haiku / DeepSeek V4 Flash / gpt-5.4-mini)
|
|
11
|
+
# @general-paid → role: quality (Opus 4.7 / DeepSeek V4 Flash / gpt-5.4)
|
|
12
|
+
# @glm-minimal → role: minimal (Haiku / DeepSeek V4 Flash / gpt-5.4-nano)
|
|
15
13
|
#
|
|
16
14
|
# Override anything by adding fields here. For example, to pin Opus on
|
|
17
15
|
# Claude Code for the @general-paid (quality) role:
|
|
@@ -29,11 +27,27 @@
|
|
|
29
27
|
# provider: openai
|
|
30
28
|
# model: gpt-5.4
|
|
31
29
|
|
|
32
|
-
extends:
|
|
30
|
+
extends: standard
|
|
31
|
+
|
|
32
|
+
default:
|
|
33
|
+
targets:
|
|
34
|
+
opencode:
|
|
35
|
+
provider: opencode
|
|
36
|
+
model: opencode-go/deepseek-v4-flash
|
|
33
37
|
|
|
34
38
|
roles:
|
|
35
39
|
fast:
|
|
36
40
|
targets:
|
|
37
41
|
opencode:
|
|
38
42
|
provider: opencode
|
|
39
|
-
model: opencode/
|
|
43
|
+
model: opencode-go/deepseek-v4-flash
|
|
44
|
+
quality:
|
|
45
|
+
targets:
|
|
46
|
+
opencode:
|
|
47
|
+
provider: opencode
|
|
48
|
+
model: opencode-go/deepseek-v4-flash
|
|
49
|
+
minimal:
|
|
50
|
+
targets:
|
|
51
|
+
opencode:
|
|
52
|
+
provider: opencode
|
|
53
|
+
model: opencode-go/deepseek-v4-flash
|
package/modes/apply.md
CHANGED
|
@@ -17,7 +17,7 @@ Live application assistant. Reads the active application form in Chrome (via Geo
|
|
|
17
17
|
why: prior aborted subagents leave Chromium sessions stuck in the pool; next `geometra_connect` fails with "Not connected" (see root `[H3]`)
|
|
18
18
|
|
|
19
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. Do not start the next round until both current-round subagents return final outcomes (`APPLIED`, `APPLY FAILED`, `SKIP`, `Discarded`, or a written TSV path); task/session ids are only launch receipts.
|
|
20
|
-
why:
|
|
20
|
+
why: subagent post-cleanup cost and portal state make racing more than 2 unreliable (see root `[H1]`). A 2026-04-25 OpenCode trace launched round 2 while round 1 was still running, then lost two provider recoveries
|
|
21
21
|
|
|
22
22
|
## Defaults
|
|
23
23
|
|
|
@@ -46,10 +46,10 @@ Live application assistant. Reads the active application form in Chrome (via Geo
|
|
|
46
46
|
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 modes/reference-portals.md.
|
|
47
47
|
|
|
48
48
|
- [D8] Upgrade application routing to `@general-paid` when the offer score is ≥ 4.0/5, the user flags "top-tier", "dream job", or "high-stakes", or the candidate is late-stage/post-screen.
|
|
49
|
-
why:
|
|
49
|
+
why: high-stakes applications need the quality-sensitive prompt and medium reasoning budget even though OpenCode now routes both application tiers through DeepSeek V4 Flash by default
|
|
50
50
|
|
|
51
|
-
- [D9] If
|
|
52
|
-
why: OpenCode
|
|
51
|
+
- [D9] If a subagent fails with provider-side errors, do not auto-downgrade or re-dispatch the same URL. Report the provider failure, leave any TSV untouched unless there is a confirmed outcome, and inspect telemetry before retrying.
|
|
52
|
+
why: OpenCode now pins all JobForge application tiers to DeepSeek V4 Flash; switching `@general-paid` → `@general-free` changes the prompt/tool budget but not the provider route, so automatic duplicate dispatches add risk without fixing provider availability
|
|
53
53
|
|
|
54
54
|
## Procedure
|
|
55
55
|
|
|
@@ -65,7 +65,7 @@ Live application assistant. Reads the active application form in Chrome (via Geo
|
|
|
65
65
|
10. Generate answers from Block B + Block F + Section G + JD.
|
|
66
66
|
11. Submit as ONE `run_actions` call [H1] using labels [D6] with `imeFriendly: true` [D4].
|
|
67
67
|
12. On session error, run the 4-step recovery; only one retry [H2].
|
|
68
|
-
13. On
|
|
68
|
+
13. On provider failure, stop and inspect telemetry before any retry [D9].
|
|
69
69
|
14. On OTP prompt, fetch the code from Gmail via `gmail_get_message`.
|
|
70
70
|
15. Submit the OTP with `geometra_fill_otp` and click Submit.
|
|
71
71
|
16. Write outcome as `batch/tracker-additions/*.tsv` [H3].
|
|
@@ -98,7 +98,7 @@ Or, on failure:
|
|
|
98
98
|
APPLY FAILED AFTER RECOVERY: <url>
|
|
99
99
|
Error 1: <first error>
|
|
100
100
|
Error 2: <post-recovery error>
|
|
101
|
-
Recommend:
|
|
101
|
+
Recommend: inspect telemetry before retrying this URL
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
---
|
|
@@ -176,7 +176,10 @@ When `location_constraints` is absent, use the prose fields:
|
|
|
176
176
|
|
|
177
177
|
```
|
|
178
178
|
Step 1 — Build the job list (N items)
|
|
179
|
-
Step 2 — Dedup:
|
|
179
|
+
Step 2 — Dedup: for each candidate, grep all four sources for the URL and for company+role:
|
|
180
|
+
data/pipeline.md, all data/applications/*.md day files,
|
|
181
|
+
batch/tracker-additions/*.tsv, batch/tracker-additions/merged/*.tsv.
|
|
182
|
+
Drop any already APPLIED before counting toward N; pick replacements from the remaining list.
|
|
180
183
|
Step 3 — geometra_list_sessions() + geometra_disconnect({closeBrowser: true}) [once, before loop]
|
|
181
184
|
Step 4 — For round in ceil(N/2):
|
|
182
185
|
pair = jobs[round*2 : round*2 + 2]
|
|
@@ -192,7 +195,7 @@ Step 6 — Reconcile outcomes (Hard Limit #6):
|
|
|
192
195
|
Step 7 — Summarize outcomes; do NOT auto-retry failures.
|
|
193
196
|
```
|
|
194
197
|
|
|
195
|
-
If a subagent fails, report it in the summary and let the user decide whether to retry. Never auto-retry — re-running a submit step risks duplicate applications.
|
|
198
|
+
If a subagent fails, report it in the summary and let the user decide whether to retry. Never auto-retry — re-running a submit step risks duplicate applications. If a subagent returns SKIP because it discovered a duplicate, treat that as a missed preflight check: finish the current round, then choose a replacement candidate only after re-running dedupe against all four sources.
|
|
196
199
|
|
|
197
200
|
**Outcome routing (Hard Limit #6 in `AGENTS.md`):**
|
|
198
201
|
- Subagents write `batch/tracker-additions/{num}-{slug}.tsv` — one TSV per job.
|
|
@@ -359,10 +362,10 @@ Call 4: geometra_run_actions({
|
|
|
359
362
|
APPLY FAILED AFTER RECOVERY: <URL>
|
|
360
363
|
Error 1: <first error message>
|
|
361
364
|
Error 2: <error after recovery>
|
|
362
|
-
Recommend:
|
|
365
|
+
Recommend: inspect telemetry before retrying this URL
|
|
363
366
|
```
|
|
364
367
|
|
|
365
|
-
Do NOT try a third time. Do NOT try a different approach. The orchestrator will decide whether to
|
|
368
|
+
Do NOT try a third time. Do NOT try a different approach. The orchestrator will decide whether to retry after inspecting telemetry.
|
|
366
369
|
|
|
367
370
|
### Skip schema re-fetches mid-flow (Rule D)
|
|
368
371
|
|
package/opencode.json
CHANGED
|
@@ -1,33 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://opencode.ai/config.json",
|
|
3
|
-
"model": "
|
|
3
|
+
"model": "opencode-go/deepseek-v4-flash",
|
|
4
4
|
"agent": {
|
|
5
5
|
"fast": {
|
|
6
|
-
"model": "opencode/
|
|
6
|
+
"model": "opencode-go/deepseek-v4-flash"
|
|
7
7
|
},
|
|
8
8
|
"quality": {
|
|
9
|
-
"model": "
|
|
9
|
+
"model": "opencode-go/deepseek-v4-flash"
|
|
10
10
|
},
|
|
11
11
|
"minimal": {
|
|
12
|
-
"model": "
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"provider": {
|
|
16
|
-
"openrouter": {
|
|
17
|
-
"models": {
|
|
18
|
-
"qwen/qwen3-coder:free": {},
|
|
19
|
-
"z-ai/glm-4.5-air:free": {},
|
|
20
|
-
"qwen/qwen3-next-80b-a3b-instruct:free": {},
|
|
21
|
-
"openai/gpt-oss-20b:free": {},
|
|
22
|
-
"openai/gpt-oss-120b:free": {},
|
|
23
|
-
"minimax/minimax-m2.5:free": {},
|
|
24
|
-
"nvidia/nemotron-3-super-120b-a12b:free": {},
|
|
25
|
-
"nvidia/nemotron-3-nano-30b-a3b:free": {},
|
|
26
|
-
"nvidia/nemotron-nano-9b-v2:free": {},
|
|
27
|
-
"google/gemma-4-26b-a4b-it:free": {},
|
|
28
|
-
"google/gemma-4-31b-it:free": {},
|
|
29
|
-
"meta-llama/llama-3.3-70b-instruct:free": {}
|
|
30
|
-
}
|
|
12
|
+
"model": "opencode-go/deepseek-v4-flash"
|
|
31
13
|
}
|
|
32
14
|
},
|
|
33
15
|
"mcp": {
|
|
@@ -66,11 +48,8 @@
|
|
|
66
48
|
}
|
|
67
49
|
}
|
|
68
50
|
},
|
|
69
|
-
"plugin": [
|
|
70
|
-
"@razroo/opencode-model-fallback"
|
|
71
|
-
],
|
|
72
51
|
"instructions": [
|
|
73
52
|
"templates/states.yml"
|
|
74
53
|
],
|
|
75
|
-
"small_model": "
|
|
54
|
+
"small_model": "opencode-go/deepseek-v4-flash"
|
|
76
55
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "job-forge",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.13",
|
|
4
4
|
"description": "AI-powered job search pipeline built on opencode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -97,7 +97,6 @@
|
|
|
97
97
|
"@razroo/iso": "^0.2.5",
|
|
98
98
|
"@razroo/iso-eval": "^0.4.0",
|
|
99
99
|
"@razroo/iso-harness": "^0.6.1",
|
|
100
|
-
"@razroo/iso-route": "^0.5.3"
|
|
101
|
-
"@razroo/opencode-model-fallback": "^0.3.1"
|
|
100
|
+
"@razroo/iso-route": "^0.5.3"
|
|
102
101
|
}
|
|
103
102
|
}
|
|
@@ -21,9 +21,9 @@ const checks = [
|
|
|
21
21
|
["H7 distrusts subagent prose", () => every(files.instructions, ["must originate from a file", "not from prior subagent prose"])],
|
|
22
22
|
["shared prompt points to on-demand references", () => every(files.instructions, ["modes/{mode}.md", "modes/reference-setup.md", "modes/reference-portals.md", "modes/reference-geometra.md"])],
|
|
23
23
|
["apply mode owns high-stakes upgrade", () => every(files.apply, ["[D8]", "@general-paid", "4.0/5", "high-stakes"])],
|
|
24
|
-
["apply mode
|
|
25
|
-
["models policy
|
|
26
|
-
["OpenCode fallback plugin is configured", () => every(files.config, ["opencodeModelFallback", "@razroo/opencode-model-fallback"])],
|
|
24
|
+
["apply mode blocks provider auto-downgrade", () => every(files.apply, ["[D9]", "do not auto-downgrade", "inspect telemetry before retrying"])],
|
|
25
|
+
["models policy pins OpenCode to DeepSeek V4 Flash", () => /extends:\s*standard/.test(files.models) && count(files.models, "opencode-go/deepseek-v4-flash") >= 4],
|
|
26
|
+
["OpenCode fallback plugin is not configured", () => !every(files.config, ["opencodeModelFallback", "@razroo/opencode-model-fallback"])],
|
|
27
27
|
];
|
|
28
28
|
|
|
29
29
|
const failures = checks
|
|
@@ -41,3 +41,7 @@ console.log(`JobForge iso smoke passed (${checks.length} checks).`);
|
|
|
41
41
|
function every(source, needles) {
|
|
42
42
|
return needles.every((needle) => source.includes(needle));
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
function count(source, needle) {
|
|
46
|
+
return source.split(needle).length - 1;
|
|
47
|
+
}
|