job-forge 2.0.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/.codex/config.toml +8 -0
- package/.cursor/mcp.json +21 -0
- package/.cursor/rules/main.mdc +519 -0
- package/.mcp.json +21 -0
- package/.opencode/agents/general-free.md +85 -0
- package/.opencode/agents/general-paid.md +39 -0
- package/.opencode/agents/glm-minimal.md +50 -0
- package/.opencode/skills/job-forge.md +185 -0
- package/AGENTS.md +514 -0
- package/CLAUDE.md +514 -0
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/batch/README.md +60 -0
- package/batch/batch-prompt.md +399 -0
- package/batch/batch-runner.sh +673 -0
- package/bin/create-job-forge.mjs +375 -0
- package/bin/job-forge.mjs +120 -0
- package/bin/sync.mjs +141 -0
- package/config/profile.example.yml +67 -0
- package/cv-sync-check.mjs +128 -0
- package/dedup-tracker.mjs +201 -0
- package/docs/ARCHITECTURE.md +220 -0
- package/docs/CUSTOMIZATION.md +101 -0
- package/docs/MODEL-ROUTING.md +195 -0
- package/docs/README.md +54 -0
- package/docs/SETUP.md +186 -0
- package/docs/demo.gif +0 -0
- package/fonts/dm-sans-latin-ext.woff2 +0 -0
- package/fonts/dm-sans-latin.woff2 +0 -0
- package/fonts/space-grotesk-latin-ext.woff2 +0 -0
- package/fonts/space-grotesk-latin.woff2 +0 -0
- package/generate-pdf.mjs +168 -0
- package/iso/agents/general-free.md +90 -0
- package/iso/agents/general-paid.md +44 -0
- package/iso/agents/glm-minimal.md +55 -0
- package/iso/commands/job-forge.md +188 -0
- package/iso/config.json +7 -0
- package/iso/instructions.md +514 -0
- package/iso/mcp.json +15 -0
- package/merge-tracker.mjs +377 -0
- package/modes/README.md +30 -0
- package/modes/_shared-calibration.md +26 -0
- package/modes/_shared.md +272 -0
- package/modes/apply.md +257 -0
- package/modes/auto-pipeline.md +70 -0
- package/modes/batch.md +110 -0
- package/modes/compare.md +23 -0
- package/modes/contact.md +82 -0
- package/modes/deep.md +99 -0
- package/modes/followup.md +68 -0
- package/modes/negotiation.md +146 -0
- package/modes/offer.md +199 -0
- package/modes/pdf.md +121 -0
- package/modes/pipeline.md +83 -0
- package/modes/project.md +30 -0
- package/modes/rejection.md +92 -0
- package/modes/scan.md +185 -0
- package/modes/tracker.md +31 -0
- package/modes/training.md +27 -0
- package/normalize-statuses.mjs +152 -0
- package/opencode.json +28 -0
- package/package.json +78 -0
- package/scripts/add-tags.mjs +894 -0
- package/scripts/cursor-agent-loop.sh +211 -0
- package/scripts/cursor-agent-stream-format.py +134 -0
- package/scripts/next-num.mjs +33 -0
- package/scripts/release/check-source.mjs +37 -0
- package/scripts/render-report-header.mjs +78 -0
- package/scripts/session-report.mjs +129 -0
- package/scripts/slugify.mjs +27 -0
- package/scripts/today.mjs +20 -0
- package/scripts/token-usage-report.mjs +315 -0
- package/scripts/tracker-line.mjs +67 -0
- package/scripts/verify-greenhouse-urls.mjs +195 -0
- package/templates/cv-template.html +395 -0
- package/templates/portals.example.yml +3140 -0
- package/templates/states.yml +62 -0
- package/tracker-lib.mjs +257 -0
- package/verify-pipeline.mjs +267 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Customization Guide
|
|
2
|
+
|
|
3
|
+
> **Note on customizing mode files.** In a consumer project (scaffolded via `npx create-job-forge`), `modes/` is a symlink to `node_modules/job-forge/modes/`. If you edit a file through the symlink you're editing the shared harness copy, which gets overwritten on the next `npm update job-forge`. To customize a specific mode file locally, **remove the symlink and replace it with a real copy**:
|
|
4
|
+
>
|
|
5
|
+
> ```bash
|
|
6
|
+
> cp node_modules/job-forge/modes/_shared.md modes/_shared.md.new
|
|
7
|
+
> rm modes/_shared.md # remove the symlink (breaks the whole modes/ dir link)
|
|
8
|
+
> mkdir -p modes # recreate as a real dir
|
|
9
|
+
> cp node_modules/job-forge/modes/*.md modes/
|
|
10
|
+
> mv modes/_shared.md.new modes/_shared.md
|
|
11
|
+
> # edit modes/_shared.md — npx job-forge sync will leave it alone from now on
|
|
12
|
+
> ```
|
|
13
|
+
>
|
|
14
|
+
> A cleaner path is to keep customization in `config/profile.yml` where possible (the shared mode files already read from it). Open an issue against `razroo/JobForge` if a piece of personal data is currently stuck in a mode file and ought to be in `profile.yml`.
|
|
15
|
+
|
|
16
|
+
## Profile (config/profile.yml)
|
|
17
|
+
|
|
18
|
+
The `config/profile.yml` file is the single source of truth for your identity. All modes read from here.
|
|
19
|
+
|
|
20
|
+
Key sections:
|
|
21
|
+
|
|
22
|
+
- **candidate**: Name, email, phone, location, LinkedIn, portfolio.
|
|
23
|
+
- **target_roles**: Your North Star roles and archetypes.
|
|
24
|
+
- **narrative**: Your headline, exit story, superpowers, proof points.
|
|
25
|
+
- **compensation**: Target range, minimum, currency.
|
|
26
|
+
- **location**: Country, timezone, visa status, on-site availability.
|
|
27
|
+
|
|
28
|
+
## Target Roles (modes/_shared.md)
|
|
29
|
+
|
|
30
|
+
The archetype table in `_shared.md` determines how offers are scored and CVs are framed. Edit the table to match YOUR career targets:
|
|
31
|
+
|
|
32
|
+
```markdown
|
|
33
|
+
| Archetype | Thematic axes | What they buy |
|
|
34
|
+
|-----------|---------------|---------------|
|
|
35
|
+
| **Your Role 1** | key skills | what they need |
|
|
36
|
+
| **Your Role 2** | key skills | what they need |
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Also update the "Adaptive Framing" table to map YOUR specific projects to each archetype.
|
|
40
|
+
|
|
41
|
+
## Portals (portals.yml)
|
|
42
|
+
|
|
43
|
+
Copy from `templates/portals.example.yml` and customize:
|
|
44
|
+
|
|
45
|
+
1. **title_filter.positive**: Keywords matching your target roles
|
|
46
|
+
2. **title_filter.negative**: Tech stacks or domains to exclude
|
|
47
|
+
3. **search_queries**: WebSearch queries for job boards (Ashby, Greenhouse, Lever)
|
|
48
|
+
4. **tracked_companies**: Companies to check directly
|
|
49
|
+
|
|
50
|
+
## CV Template (templates/cv-template.html)
|
|
51
|
+
|
|
52
|
+
The HTML template uses these design tokens:
|
|
53
|
+
- **Fonts**: Space Grotesk (headings) + DM Sans (body) -- self-hosted in `fonts/`
|
|
54
|
+
- **Colors**: Cyan primary (`hsl(187,74%,32%)`) + Purple accent (`hsl(270,70%,45%)`)
|
|
55
|
+
- **Layout**: Single-column, ATS-optimized
|
|
56
|
+
|
|
57
|
+
To customize fonts/colors, edit the CSS in the template. Update font files in `fonts/` if switching fonts.
|
|
58
|
+
|
|
59
|
+
## Examples (`examples/`)
|
|
60
|
+
|
|
61
|
+
Fictional samples for structure and tone — not real candidates. See [`examples/README.md`](../examples/README.md) for markdown CVs, an optional article-digest example, and a sample report layout. Use them as templates, then replace every detail with your own before applying.
|
|
62
|
+
|
|
63
|
+
## Interview prep (`interview-prep/story-bank.md`)
|
|
64
|
+
|
|
65
|
+
Optional file that holds curated STAR+R stories across evaluations. Modes that produce interview prep (for example Block F in a single-offer evaluation) can append or reference stories here so you reuse the same narratives instead of starting from scratch before each interview. The shipped file is a scaffold with formatting comments; replace placeholders with your own content as the bank fills in. If you prefer a different path, keep the same structure and point your workflow at your copy.
|
|
66
|
+
|
|
67
|
+
## Negotiation Scripts (modes/_shared.md)
|
|
68
|
+
|
|
69
|
+
The negotiation section provides frameworks for salary discussions. Replace the example scripts with your own:
|
|
70
|
+
- Target ranges
|
|
71
|
+
- Geographic arbitrage strategy
|
|
72
|
+
- Pushback responses
|
|
73
|
+
|
|
74
|
+
## Hooks (Optional)
|
|
75
|
+
|
|
76
|
+
JobForge can integrate with external systems via opencode hooks. Example hooks:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"hooks": {
|
|
81
|
+
"SessionStart": [{
|
|
82
|
+
"hooks": [{
|
|
83
|
+
"type": "command",
|
|
84
|
+
"command": "echo 'JobForge session started'"
|
|
85
|
+
}]
|
|
86
|
+
}]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Save hooks in `.opencode/settings.json`.
|
|
92
|
+
|
|
93
|
+
## States (templates/states.yml)
|
|
94
|
+
|
|
95
|
+
The canonical states rarely need changing. Since `templates/` is a symlink into the harness in consumer projects, adding new states means contributing back to `razroo/JobForge` (see [CONTRIBUTING.md](../CONTRIBUTING.md)). If you're working in the harness repo directly (Path B), update:
|
|
96
|
+
|
|
97
|
+
1. `templates/states.yml`
|
|
98
|
+
2. `normalize-statuses.mjs` (alias mappings)
|
|
99
|
+
3. `modes/_shared.md` (any references)
|
|
100
|
+
4. `merge-tracker.mjs` — TSV merges validate the status column against labels in `templates/states.yml`; extend the parser or built-in fallbacks there if you add states before running `npx job-forge merge` / `npm run merge`; see [batch/README.md](../batch/README.md)
|
|
101
|
+
5. `verify-pipeline.mjs` — extend `CANONICAL_STATUSES` (and `ALIASES` when you add new status aliases) so the health check stays aligned with `states.yml`; see [Architecture — Pipeline Integrity](ARCHITECTURE.md#pipeline-integrity)
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Model Routing
|
|
2
|
+
|
|
3
|
+
JobForge routes each piece of work to the cheapest model that can do it well, instead of running every tool call on one expensive model. This doc explains why that matters, how the routing is wired, and how to customize it.
|
|
4
|
+
|
|
5
|
+
## Why routing matters (the cost math)
|
|
6
|
+
|
|
7
|
+
A two-day trace early in development showed `$48` in spend, with **84% coming from GLM 5.1** despite the majority of the work being procedural (form fills, tracker updates, OTP retrieval). The root cause:
|
|
8
|
+
|
|
9
|
+
- **GLM 5.1's provider doesn't discount cache reads.** On Anthropic, a 10K-token cached prefix costs ~$0.03. On GLM 5.1 it bills near-full input rate (~$0.35). Every session that re-loads the prefix pays full price.
|
|
10
|
+
- **Procedural work is the high-volume work.** 1000+ messages per day go to form filling, TSV merges, scan dedup. Running that on GLM 5.1 is ~10× more expensive than running it on a free-tier model that can handle the task just fine.
|
|
11
|
+
- **Free-tier opencode models are genuinely free and genuinely capable.** `opencode/big-pickle` processed 1000+ messages at $0 over the same window with acceptable quality on procedural tasks.
|
|
12
|
+
|
|
13
|
+
Conclusion: route procedural work to free tier, reserve paid models for tasks that actually need the quality.
|
|
14
|
+
|
|
15
|
+
## The three subagents
|
|
16
|
+
|
|
17
|
+
Defined in `.opencode/agents/*.md` (shipped in the harness, symlinked into consumers by `job-forge sync`):
|
|
18
|
+
|
|
19
|
+
| Agent | Model | Reasoning | Use for |
|
|
20
|
+
|-------|-------|-----------|---------|
|
|
21
|
+
| `@general-free` | `opencode/big-pickle` (free) | `minimal` | Geometra form fills, tracker TSV merges, scan dedup, OTP retrieval via Gmail, scripted pipeline steps |
|
|
22
|
+
| `@general-paid` | `opencode/glm-5.1` | `medium` | Offer evaluation narratives (Blocks A-F), cover letters, "Why X?" answers, STAR+R interview stories, LinkedIn outreach prose |
|
|
23
|
+
| `@glm-minimal` | `opencode/minimax-m2.5-free` (free) | `none` | Narrow one-shot transforms: "extract these 8 fields from this JD text → JSON", "classify this archetype" |
|
|
24
|
+
|
|
25
|
+
The full task-to-agent mapping lives in [AGENTS.md → Subagent Routing](../AGENTS.md#subagent-routing--which-agent-for-which-task). The orchestrator (your primary session) is expected to delegate before taking any multi-step action — see the **Pre-flight delegation** rule in AGENTS.md.
|
|
26
|
+
|
|
27
|
+
## How the routing is enforced
|
|
28
|
+
|
|
29
|
+
Four layers, each reinforcing the others:
|
|
30
|
+
|
|
31
|
+
**1. Permission layer** (`opencode.json:permission.task`):
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"permission": {
|
|
35
|
+
"task": {
|
|
36
|
+
"general-free": "allow",
|
|
37
|
+
"general-paid": "allow",
|
|
38
|
+
"glm-minimal": "allow"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
The orchestrator can only dispatch to these three agents. Accidental self-calls or hallucinated agent names fail loudly.
|
|
44
|
+
|
|
45
|
+
**2. Tool surface trim** (`opencode.json:tools` + per-agent `tools:`):
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"tools": {
|
|
49
|
+
"geometra_*": false,
|
|
50
|
+
"gmail_*": false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
Disables ~30 MCP tool schemas globally; each agent re-enables only what it needs in its own `.opencode/agents/<name>.md` frontmatter. Saves ~2-3K input tokens per request in the orchestrator.
|
|
55
|
+
|
|
56
|
+
**3. Thinking budgets** (`reasoningEffort` in agent frontmatter):
|
|
57
|
+
- `@general-free`: `minimal` — procedural work shouldn't need chain-of-thought
|
|
58
|
+
- `@general-paid`: `medium` — writing quality benefits from thinking
|
|
59
|
+
- `@glm-minimal`: `none` — pure transforms, emit and exit
|
|
60
|
+
|
|
61
|
+
**4. Prompt rules** (in each agent's `.md` body): explicit instructions on working style, what to do and not do, and structured output expectations.
|
|
62
|
+
|
|
63
|
+
## Customizing the routing
|
|
64
|
+
|
|
65
|
+
All three layers are designed to be edited — this is your search, your cost budget, your model preferences.
|
|
66
|
+
|
|
67
|
+
### Swap the paid model
|
|
68
|
+
|
|
69
|
+
The default `@general-paid` is `opencode/glm-5.1`. To use Claude instead, edit `.opencode/agents/general-paid.md`:
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
---
|
|
73
|
+
model: opencode/claude-sonnet-4-6
|
|
74
|
+
reasoningEffort: medium
|
|
75
|
+
---
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The `.opencode/agents/general-paid.md` file is a symlink into `node_modules/job-forge/` by default. To customize locally without modifying the harness: delete the symlink and create a real file with the same name — `job-forge sync` will skip it on future updates. Or override in `opencode.json` under `agent.general-paid.model`.
|
|
79
|
+
|
|
80
|
+
### Swap the free tier
|
|
81
|
+
|
|
82
|
+
Same idea — edit `.opencode/agents/general-free.md`'s `model:` field. `opencode/minimax-m2.5-free` is another zero-cost option the data shows handles ~900 messages per day cleanly. If you run into quality issues on forms, bump this agent's model to a small paid tier (e.g., Haiku) rather than routing everything through paid.
|
|
83
|
+
|
|
84
|
+
### Add a custom agent
|
|
85
|
+
|
|
86
|
+
Create `.opencode/agents/my-agent.md` with the same frontmatter shape, then allow-list it in `opencode.json:permission.task`:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"permission": {
|
|
91
|
+
"task": {
|
|
92
|
+
"general-free": "allow",
|
|
93
|
+
"general-paid": "allow",
|
|
94
|
+
"glm-minimal": "allow",
|
|
95
|
+
"my-agent": "allow"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Change what tools an agent can call
|
|
102
|
+
|
|
103
|
+
Edit the `tools:` block in the agent's frontmatter. Use globs to allow-list families (`gmail_*: true`) or individual names (`geometra_connect: true`). Anything not explicitly re-enabled inherits the global `false`.
|
|
104
|
+
|
|
105
|
+
### Route differently per task
|
|
106
|
+
|
|
107
|
+
The task-to-agent mapping in AGENTS.md is instruction-level, not enforced by config. If you want evaluation narratives on free tier (saving cost but accepting lower writing quality), update the "Subagent Routing" table in AGENTS.md and the orchestrator will follow it.
|
|
108
|
+
|
|
109
|
+
## Verifying the routing actually works
|
|
110
|
+
|
|
111
|
+
Three commands, increasing precision:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# 1. Per-day, per-model breakdown — confirms % of cost going to each tier
|
|
115
|
+
npx job-forge tokens --days 2
|
|
116
|
+
|
|
117
|
+
# 2. Per-session breakdown since N minutes ago, with >$1 budget warning
|
|
118
|
+
npx job-forge session-report --since-minutes 60
|
|
119
|
+
|
|
120
|
+
# 3. Drill into a specific session to see which agent made which message
|
|
121
|
+
npx job-forge tokens --session <session-id>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Healthy pattern after this architecture lands:
|
|
125
|
+
- **`opencode/big-pickle`** (or your free-tier choice) handles the message majority at $0
|
|
126
|
+
- **`opencode/glm-5.1`** (or your paid choice) costs per session stay under $1 for most evaluations
|
|
127
|
+
- Session titles prefixed `@general-free`, `@general-paid`, `@glm-minimal` appear in the list — confirms delegation actually happened
|
|
128
|
+
- `cache_read` >> `cache_creation` on parallel subagent runs within a 5-min window
|
|
129
|
+
|
|
130
|
+
Failure pattern to watch for:
|
|
131
|
+
- **All messages showing up under your primary model** (no `@general-*` titles) → orchestrator isn't delegating. Check the Pre-flight delegation rule in AGENTS.md is being followed; tighten wording if not.
|
|
132
|
+
- **High cache-creation with near-zero cache-read across parallel workers** → workers aren't firing within the 5-min cache TTL, or the shared prefix isn't byte-identical (see [batch/README.md](../batch/README.md) for the prompt-cache-friendly batch pattern).
|
|
133
|
+
|
|
134
|
+
## Automatic fallback on rate limits / 5xx
|
|
135
|
+
|
|
136
|
+
A rate-limited or overloaded free-tier model would otherwise wedge the whole subagent flow — the delegated task errors and the orchestrator sits stuck. The harness ships with [`@razroo/opencode-model-fallback`](https://www.npmjs.com/package/@razroo/opencode-model-fallback) (added as a dependency in the scaffolder) to rotate agents through a configured `fallback_models` chain automatically.
|
|
137
|
+
|
|
138
|
+
Default chains ship upstream in each agent's YAML frontmatter (`node_modules/job-forge/.opencode/agents/*.md`, symlinked into your project's `.opencode/agents/`):
|
|
139
|
+
|
|
140
|
+
| Agent | Primary | Fallback chain (in order) |
|
|
141
|
+
|-------|---------|---------------------------|
|
|
142
|
+
| `@general-free` | `opencode/big-pickle` | `opencode/minimax-m2.5-free` → `opencode/nemotron-3-super-free` → `opencode-go/minimax-m2.7` → `opencode/glm-5.1` (paid escape hatch) |
|
|
143
|
+
| `@general-paid` | `opencode/glm-5.1` | `opencode/claude-haiku-4-5` |
|
|
144
|
+
| `@glm-minimal` | `opencode/minimax-m2.5-free` | `opencode/big-pickle` → `opencode/nemotron-3-super-free` |
|
|
145
|
+
|
|
146
|
+
Free-tier agents exhaust free models first, then try minimax 2.7 as a cheap buffer before escalating to glm-5.1. Paid agents fall back to Haiku (cheaper unstick escape hatch). **Note:** all model IDs use the `opencode/` or `opencode-go/` prefix — the `anthropic/` prefix does not exist in opencode's model registry and will throw `ProviderModelNotFoundError`.
|
|
147
|
+
|
|
148
|
+
Consumers **do not need to configure anything** to get these defaults: the chains arrive via the symlinked agent MD files, and `@razroo/opencode-model-fallback` (≥0.3.1) reads them from the `options.fallback_models` field that opencode relocates unknown frontmatter keys into. The consumer's `opencode.json` only needs `"plugin": ["@razroo/opencode-model-fallback"]` — which the scaffolder sets automatically.
|
|
149
|
+
|
|
150
|
+
**When fallback fires:** the plugin pattern-matches rate-limit / 5xx / quota / "overloaded" / "insufficient credits" errors. Failed models enter a 60-second cooldown before they're retried. Every rotation logs to `~/.config/opencode/opencode-model-fallback.log` with the trigger error, original model, and target model — grep for `"Auto-retrying with fallback model"` to confirm it fired.
|
|
151
|
+
|
|
152
|
+
### Overriding an upstream chain
|
|
153
|
+
|
|
154
|
+
Add an `agent.<name>.fallback_models` block to your project's `opencode.json`. Top-level entries win over upstream frontmatter:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"agent": {
|
|
159
|
+
"general-free": {
|
|
160
|
+
"fallback_models": ["my/preferred-free", "my/preferred-paid"]
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Global fallback chain (agents without their own)
|
|
167
|
+
|
|
168
|
+
Plugin-level config at `.opencode/opencode-model-fallback.json` — applies to any agent whose `fallback_models` is empty:
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"cooldown_seconds": 60,
|
|
173
|
+
"timeout_seconds": 30,
|
|
174
|
+
"notify_on_fallback": true,
|
|
175
|
+
"fallback_models": ["opencode/minimax-m2.5-free", "opencode/glm-5.1"]
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Disabling fallback
|
|
180
|
+
|
|
181
|
+
Remove `"@razroo/opencode-model-fallback"` from `opencode.json:plugin` — agents keep their `model:` primary and errors propagate normally.
|
|
182
|
+
|
|
183
|
+
## Known limitations
|
|
184
|
+
|
|
185
|
+
- **opencode's 5-minute cache TTL is hardcoded.** The 1-hour cache (Anthropic beta, `extended-cache-ttl-2025-04-11`) is not plumbed through opencode as of 2026-04-15. Long batch runs (>5 min between workers) will miss cache every cycle. Upstream fix would be 2 lines in `packages/opencode/src/provider/`.
|
|
186
|
+
- **`instructions` is top-level, not per-agent.** Files listed in `opencode.json:instructions` load for every agent including free-tier. This is fine for `cv.md` and `_shared.md` (they're small and useful everywhere), but means you can't hide heavy context from free agents via instructions — use per-agent `prompt:` files for that.
|
|
187
|
+
- **`reasoningEffort` support varies by provider.** Anthropic accepts `thinking: { type: "disabled" }`; opencode-labs models may need the `variant` pattern. See the `reasoningEffort` values in the opencode docs.
|
|
188
|
+
|
|
189
|
+
## See also
|
|
190
|
+
|
|
191
|
+
- [AGENTS.md — Subagent Routing](../AGENTS.md#subagent-routing--which-agent-for-which-task) — the task-to-agent mapping table
|
|
192
|
+
- [AGENTS.md — Pre-flight delegation](../AGENTS.md#pre-flight-delegation-hard-rule) — the "first tool call must be `task`" rule
|
|
193
|
+
- [ARCHITECTURE.md](ARCHITECTURE.md) — how modes, symlinks, and the consumer/harness split fit together
|
|
194
|
+
- [CUSTOMIZATION.md](CUSTOMIZATION.md) — archetype, CV template, portal, and state customization
|
|
195
|
+
- `.opencode/agents/` — the three agent definitions (YAML frontmatter + markdown prompt body)
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# JobForge documentation
|
|
2
|
+
|
|
3
|
+
Guides for installing JobForge, understanding how pieces fit together, and tailoring the system to your search. Use this file as the entry point when browsing the `docs/` folder on GitHub or locally.
|
|
4
|
+
|
|
5
|
+
## Install paths
|
|
6
|
+
|
|
7
|
+
JobForge ships as an installable package (v2.0.0+). Pick the path that matches your goal:
|
|
8
|
+
|
|
9
|
+
| Path | Who it's for | How |
|
|
10
|
+
|------|--------------|-----|
|
|
11
|
+
| **A — Scaffold a personal project** | Most users. You want a job search project with the harness in `node_modules`, updatable via `npm update job-forge`. | `npx github:razroo/JobForge create-job-forge my-search && cd my-search && npm install` |
|
|
12
|
+
| **B — Clone the harness directly** | Contributors and hackers working on modes, scripts, or the scoring model. Personal files are gitignored. | `git clone https://github.com/razroo/JobForge.git && cd JobForge && npm install` |
|
|
13
|
+
|
|
14
|
+
See [SETUP.md](SETUP.md) for both paths.
|
|
15
|
+
|
|
16
|
+
## Guides
|
|
17
|
+
|
|
18
|
+
| Guide | What it covers |
|
|
19
|
+
|-------|----------------|
|
|
20
|
+
| [SETUP.md](SETUP.md) | Prerequisites, both install paths, profile and CV, portals, `npx job-forge verify`, optional Go dashboard, token usage tracking, [troubleshooting](SETUP.md#troubleshooting) |
|
|
21
|
+
| [ARCHITECTURE.md](ARCHITECTURE.md) | [Package architecture](ARCHITECTURE.md#package-architecture-v200) (consumer vs harness split), modes under `modes/`, single-offer flow, batch runner, tracker and scripts, [contributor touchpoints](ARCHITECTURE.md#contributing-touchpoints) |
|
|
22
|
+
| [CUSTOMIZATION.md](CUSTOMIZATION.md) | Profile, archetypes in `_shared.md`, `portals.yml`, CV template, canonical states, optional story bank and opencode hooks. Also: how to customize a symlinked mode file locally |
|
|
23
|
+
| [MODEL-ROUTING.md](MODEL-ROUTING.md) | Why the harness uses three cost-tiered subagents (`@general-free`, `@general-paid`, `@glm-minimal`), how routing is enforced (permission + tool-surface trim + reasoningEffort), how to swap models or add agents, and the automatic fallback-on-rate-limit behavior via [`@razroo/opencode-model-fallback`](https://www.npmjs.com/package/@razroo/opencode-model-fallback) |
|
|
24
|
+
| [examples/README.md](../examples/README.md) | Fictional CV samples (per-role markdown), optional digest, fictional [`sample-jd.md`](../examples/sample-jd.md) for `local:jds/…` shape, and sample report — starting point for new `cv.md`, JD-on-disk layout, or contributor archetypes (cloud infrastructure, agent platform) |
|
|
25
|
+
| [batch/README.md](../batch/README.md) | Batch TSV format, `batch-runner.sh`, `tracker-additions/` merge flow with `npx job-forge merge` |
|
|
26
|
+
| [jds/README.md](../jds/README.md) | Markdown JDs on disk; `local:jds/{file}.md` lines in `data/pipeline.md` |
|
|
27
|
+
|
|
28
|
+
## Commands and automation
|
|
29
|
+
|
|
30
|
+
The harness exposes a single CLI (`job-forge`) installed as a `bin` entry. In a consumer project, `npx job-forge <cmd>` invokes any of the scripts; npm script aliases (`npm run verify`, `npm run merge`, `npm run dedup`, `npm run normalize`) are wired up in the scaffolded `package.json`. In the harness repo (Path B), scripts run directly via `node <script>.mjs` or their npm aliases.
|
|
31
|
+
|
|
32
|
+
| What you need | Where to read |
|
|
33
|
+
|---------------|---------------|
|
|
34
|
+
| Full command list (`verify`, `merge`, `dedup`, `normalize`, `pdf`, `sync-check`, `tokens`, `sync`). | [SETUP.md — Tracker and scripts (terminal)](SETUP.md#tracker-and-scripts-terminal). |
|
|
35
|
+
| What each harness `.mjs` script does. | [ARCHITECTURE.md — Pipeline integrity](ARCHITECTURE.md#pipeline-integrity) and the scripts table underneath. |
|
|
36
|
+
| Batch runner, TSV layout, and `batch/tracker-additions/` merge flow. | [batch/README.md](../batch/README.md). |
|
|
37
|
+
| PR gate for harness contributions (`npm run verify` + `npm run build:dashboard`). | [CONTRIBUTING.md — Development](../CONTRIBUTING.md#development). |
|
|
38
|
+
| Optional scripted iterations (harness repo only). | [scripts/cursor-agent-loop.sh](../scripts/cursor-agent-loop.sh). Usage and env vars live in the script header and in [CONTRIBUTING.md — Optional: scripted agent iterations](../CONTRIBUTING.md#optional-scripted-agent-iterations). Verbose JSON output is formatted by [cursor-agent-stream-format.py](../scripts/cursor-agent-stream-format.py). |
|
|
39
|
+
| Work-marker search (`T`ODO, `F`IXME, `H`ACK strings in the source) before picking work. | [CONTRIBUTING.md — Optional: scripted agent iterations](../CONTRIBUTING.md#optional-scripted-agent-iterations) — `rg` one-liner from the harness repo root. |
|
|
40
|
+
|
|
41
|
+
## Related material (harness repo root)
|
|
42
|
+
|
|
43
|
+
- [modes/README.md](../modes/README.md) — per-command prompts used with the skill router (archetypes and shared scoring live in `_shared.md`; see **Modes** in [ARCHITECTURE.md](ARCHITECTURE.md)).
|
|
44
|
+
- [.opencode/skills/job-forge.md](../.opencode/skills/job-forge.md) — the skill router that routes `/job-forge <mode>` to the right prompt and loads only the data files that mode needs.
|
|
45
|
+
- [CONTRIBUTING.md](../CONTRIBUTING.md) — branch workflow, quality gate, contribution ideas.
|
|
46
|
+
- [templates/states.yml](../templates/states.yml) — canonical tracker status ids and labels (used by verify, merge, and normalize).
|
|
47
|
+
- [templates/portals.example.yml](../templates/portals.example.yml) — starter portal and scanner config (copied into consumer projects as `portals.yml`).
|
|
48
|
+
- [templates/cv-template.html](../templates/cv-template.html) — HTML layout for ATS-style PDFs from `generate-pdf.mjs`.
|
|
49
|
+
- [config/profile.example.yml](../config/profile.example.yml) — template copied into consumer projects as `config/profile.yml`.
|
|
50
|
+
- [examples/README.md](../examples/README.md) — fictional CV samples and illustrative report layout.
|
|
51
|
+
- [interview-prep/story-bank.md](../interview-prep/story-bank.md) — optional STAR+R story bank (grows as you run evaluations).
|
|
52
|
+
- [batch/README.md](../batch/README.md) — batch TSV input, merge step, and runner prerequisites.
|
|
53
|
+
- [`data/pipeline.md`](../data/) — inbox of pending offer URLs and `local:jds/…` lines (create when you first queue a URL; see [`modes/pipeline.md`](../modes/pipeline.md)).
|
|
54
|
+
- [jds/README.md](../jds/README.md) — markdown job descriptions on disk; the pipeline references them as `local:jds/{filename}.md` from the project root.
|
package/docs/SETUP.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Setup Guide
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
- [opencode](https://opencode.ai) installed and configured
|
|
6
|
+
- Node.js 18+ (for the CLI, PDF generation, and tracker scripts)
|
|
7
|
+
- (Optional) Go (for the dashboard TUI) — use a toolchain that satisfies the `go` directive in [`dashboard/go.mod`](../dashboard/go.mod)
|
|
8
|
+
|
|
9
|
+
## Quick Start (two paths)
|
|
10
|
+
|
|
11
|
+
### Path A — Scaffold a personal project (recommended)
|
|
12
|
+
|
|
13
|
+
JobForge is distributed as an installable npm package. Use the scaffolder to create a new project that keeps only your personal data (CV, profile, portals, tracker) while the harness (modes, skills, scripts) lives in `node_modules/job-forge` and updates with one command.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 1. Scaffold
|
|
17
|
+
npx github:razroo/JobForge create-job-forge my-job-search
|
|
18
|
+
cd my-job-search
|
|
19
|
+
|
|
20
|
+
# 2. Install the harness (pulls razroo/JobForge from GitHub; postinstall
|
|
21
|
+
# creates symlinks for modes/, templates/, .opencode/skills/job-forge.md,
|
|
22
|
+
# and batch/{batch-prompt.md,batch-runner.sh,README.md})
|
|
23
|
+
npm install
|
|
24
|
+
|
|
25
|
+
# 3. Fill in personal files
|
|
26
|
+
# - cv.md (your CV in markdown)
|
|
27
|
+
# - config/profile.yml (copied from profile.example.yml — edit with your
|
|
28
|
+
# name, email, target roles, narrative, proof points)
|
|
29
|
+
# - portals.yml (copied from templates/portals.example.yml — edit keywords
|
|
30
|
+
# and tracked companies)
|
|
31
|
+
# - article-digest.md (optional; proof points with metrics)
|
|
32
|
+
|
|
33
|
+
# 4. Launch opencode
|
|
34
|
+
opencode
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The scaffolded `opencode.json` already registers the Geometra MCP (browser automation + PDF generation) and Gmail MCP (reading interview/offer replies), so they launch automatically the first time opencode starts — no `opencode mcp add` step required.
|
|
38
|
+
|
|
39
|
+
Paste a job URL or run `/job-forge` to see the command menu.
|
|
40
|
+
|
|
41
|
+
To **upgrade the harness** later:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm update job-forge # pulls latest razroo/JobForge
|
|
45
|
+
npx job-forge sync # refresh symlinks if anything drifted
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Path B — Clone the harness directly
|
|
49
|
+
|
|
50
|
+
Use this if you want to hack on the harness itself (add modes, tune the scoring model, contribute back). Personal files are gitignored.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
git clone https://github.com/razroo/JobForge.git
|
|
54
|
+
cd JobForge
|
|
55
|
+
npm install
|
|
56
|
+
|
|
57
|
+
# Add personal files the same way as Path A
|
|
58
|
+
cp config/profile.example.yml config/profile.yml
|
|
59
|
+
cp templates/portals.example.yml portals.yml
|
|
60
|
+
# Create cv.md in the project root
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
When you're inside this repo, the `postinstall` symlink step is a no-op (detected and skipped). All npm scripts run the harness code directly. The repo's `opencode.json` at the project root registers the same Geometra + Gmail MCPs as the scaffolder ships to consumers.
|
|
64
|
+
|
|
65
|
+
## Personalization
|
|
66
|
+
|
|
67
|
+
For structure and section ideas, see the fictional samples in [`examples/`](../examples/) (for example `cv-example.md`, `cv-example-backend-engineer.md`, `cv-example-fullstack-engineer.md`, `cv-example-data-engineer.md`, `cv-example-frontend-engineer.md`, `cv-example-mobile-engineer.md`, `cv-example-devops-engineer.md`, `cv-example-engineering-manager.md`, `cv-example-security-engineer.md`, `cv-example-qa-engineer.md`, `cv-example-solutions-architect.md`, and `cv-example-product-manager.md`).
|
|
68
|
+
|
|
69
|
+
> **The system is designed to be customized by opencode itself.** Modes, archetypes, scoring weights, negotiation scripts — just ask opencode to change them. See [Customization](CUSTOMIZATION.md).
|
|
70
|
+
|
|
71
|
+
## Application tracker (optional until first evaluation)
|
|
72
|
+
|
|
73
|
+
New rows go to **`data/applications/YYYY-MM-DD.md`** day files when the `data/applications/` directory exists. If it does not exist, utilities and the dashboard fall back to **`data/applications.md`** or the repo root **`applications.md`** (same column layout). A fresh setup often has neither the directory nor the file yet; that is normal, and `npx job-forge verify` still exits successfully.
|
|
74
|
+
|
|
75
|
+
To start with an empty tracker (for example before you paste your first URL), create the directory:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
mkdir -p data/applications
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The first evaluation will create a day file like `data/applications/2026-04-13.md` with this header:
|
|
82
|
+
|
|
83
|
+
```markdown
|
|
84
|
+
# Applications Tracker
|
|
85
|
+
|
|
86
|
+
| # | Date | Company | Role | Score | Status | PDF | Report | Notes |
|
|
87
|
+
|---|------|---------|------|-------|--------|-----|--------|-------|
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Status values MUST match [templates/states.yml](../templates/states.yml); see the **States** section in [Customization](CUSTOMIZATION.md). After batch evaluations, run `npx job-forge merge` to pull in `batch/tracker-additions/*.tsv` when your workflow uses those files. For the parallel batch runner that produces those additions, see [batch/README.md](../batch/README.md). If the status column has typos, old labels, or bold markers, run `npx job-forge normalize` to rewrite rows toward the canonical set (use `npx job-forge normalize --dry-run` first to preview changes).
|
|
91
|
+
|
|
92
|
+
## Available commands (opencode)
|
|
93
|
+
|
|
94
|
+
Use these inside an opencode session in your project (see the skill at `.opencode/skills/job-forge.md` for the full routing logic):
|
|
95
|
+
|
|
96
|
+
| Action | How |
|
|
97
|
+
|--------|-----|
|
|
98
|
+
| Evaluate an offer | Paste a URL or JD text |
|
|
99
|
+
| Search for offers | `/job-forge scan` |
|
|
100
|
+
| Process pending URLs | `/job-forge pipeline` |
|
|
101
|
+
| Generate a PDF | `/job-forge pdf` |
|
|
102
|
+
| Batch evaluate | `/job-forge batch` |
|
|
103
|
+
| Check tracker status | `/job-forge tracker` |
|
|
104
|
+
| Fill application form | `/job-forge apply` |
|
|
105
|
+
|
|
106
|
+
## Tracker and scripts (terminal)
|
|
107
|
+
|
|
108
|
+
From your project root, these commands maintain the tracker and pipeline checks. They do not require opencode. `merge`, `normalize`, and `dedup` exit successfully when the tracker file is missing (same as a fresh setup).
|
|
109
|
+
|
|
110
|
+
| Action | Command | npm alias |
|
|
111
|
+
|--------|---------|-----------|
|
|
112
|
+
| Pipeline health check | `npx job-forge verify` | `npm run verify` |
|
|
113
|
+
| Merge `batch/tracker-additions/*.tsv` into the tracker | `npx job-forge merge` | `npm run merge` |
|
|
114
|
+
| Map status column to canonical labels | `npx job-forge normalize` | `npm run normalize` |
|
|
115
|
+
| Merge duplicate company/role rows | `npx job-forge dedup` | `npm run dedup` |
|
|
116
|
+
| Generate ATS-optimized CV PDF | `npx job-forge pdf` | `npm run pdf` |
|
|
117
|
+
| Setup lint (cv.md + profile.yml) | `npx job-forge sync-check` | `npm run sync-check` |
|
|
118
|
+
| Token usage report (from opencode SQLite DB) | `npx job-forge tokens` | `npm run tokens` |
|
|
119
|
+
| Re-create harness symlinks | `npx job-forge sync` | `npm run sync` |
|
|
120
|
+
| Build optional dashboard TUI (Go on `PATH`) | `(cd node_modules/job-forge/dashboard && go build .)` | `npm run build:dashboard` (harness repo only) |
|
|
121
|
+
|
|
122
|
+
Path B users (cloning the harness) can keep using the shorter `npm run <script>` aliases since the scripts live at the repo root.
|
|
123
|
+
|
|
124
|
+
## Verify setup
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
npx job-forge verify # Pipeline integrity. OK if the tracker file does not exist yet; still warns on unmerged batch/tracker-additions/*.tsv — run npx job-forge merge when you intend to fold those rows into the tracker (see batch/README.md)
|
|
128
|
+
npx job-forge sync-check # Requires cv.md and config/profile.yml
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Build dashboard (optional, Path B only)
|
|
132
|
+
|
|
133
|
+
The TUI reads the tracker at the JobForge repo root (day files in `data/applications/`, or `data/applications.md`, or root `applications.md`). If you build inside `dashboard/`, point `-path` at the parent directory:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
cd dashboard
|
|
137
|
+
go build -o job-forge-dashboard .
|
|
138
|
+
./job-forge-dashboard -path .. # repo root is one level up
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
From the repo root, `npm run build:dashboard` runs `go build .` inside `dashboard/`.
|
|
142
|
+
|
|
143
|
+
Path A users who want the dashboard can either clone the harness separately or run the binary from `node_modules/job-forge/dashboard/` after `go build`.
|
|
144
|
+
|
|
145
|
+
## Token usage tracking
|
|
146
|
+
|
|
147
|
+
The harness ships a per-session token/cost report that queries opencode's SQLite database:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npx job-forge tokens # last 7 days
|
|
151
|
+
npx job-forge tokens --days 1 # today only
|
|
152
|
+
npx job-forge tokens --days 1 --append # append to data/token-usage.tsv
|
|
153
|
+
npx job-forge tokens --session <id> # drill into one session
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Use it to identify which sessions or models are consuming the most tokens. The `opencode.json` shipped with the scaffolder loads only `templates/states.yml` into every session and lets the skill router load mode/data files on demand, which typically keeps per-call input tokens at ~20-40K instead of ~130-170K.
|
|
157
|
+
|
|
158
|
+
## Troubleshooting
|
|
159
|
+
|
|
160
|
+
**`npx job-forge verify` succeeds, but `npx job-forge sync-check` fails**
|
|
161
|
+
`sync-check` requires `cv.md` and `config/profile.yml` with the fields checked in `cv-sync-check.mjs`. Until you finish the profile and CV steps, that is normal.
|
|
162
|
+
|
|
163
|
+
**PDF generation fails**
|
|
164
|
+
The scaffolded `opencode.json` already registers Geometra MCP; if it's not running, check `opencode mcp list` and verify the scaffolded config under the `mcp.geometra` key — its `command` MUST be `["npx", "-y", "@geometra/mcp"]` and `enabled: true`. Geometra manages Chromium via its built-in proxy. For standalone CLI usage (outside opencode), `generate-pdf.mjs` also works with standalone Playwright/Chromium — install with `npx playwright install chromium`.
|
|
165
|
+
|
|
166
|
+
**Symlinks are missing or pointing to a stale path**
|
|
167
|
+
Run `npx job-forge sync` (or `npm run sync`) to recreate them. This happens if you move the project directory after installing, or if `postinstall` didn't run (rare — check `npm install` output for errors).
|
|
168
|
+
|
|
169
|
+
**`npx job-forge sync` says "X already exists as a real file/dir — leaving alone"**
|
|
170
|
+
You or the scaffolder created a real file where the harness wants to put a symlink. If you want to customize that file locally, keep it as-is — the sync script preserves real files. If you want the harness version, delete your local copy and rerun `npx job-forge sync`.
|
|
171
|
+
|
|
172
|
+
**Dashboard is empty or points at the wrong data**
|
|
173
|
+
The `-path` argument must be the project root (where `data/applications/` or `data/applications.md` lives), not the `dashboard/` directory.
|
|
174
|
+
|
|
175
|
+
**`go build` reports `go: command not found` or a version error**
|
|
176
|
+
Install Go and put it on your `PATH`, or omit the dashboard; everything else runs with Node.js.
|
|
177
|
+
|
|
178
|
+
**`npx job-forge merge` says there is nothing to merge, but you have TSV files**
|
|
179
|
+
Only files directly under `batch/tracker-additions/` with a `.tsv` extension are picked up. After a successful merge, rows are merged into the tracker and those files move to `batch/tracker-additions/merged/`, so a second run correctly finds nothing left. If you created TSVs elsewhere or only have files under `merged/`, move or regenerate them in the top-level `tracker-additions` folder (see [batch/README.md](../batch/README.md)).
|
|
180
|
+
|
|
181
|
+
**A `local:jds/...` line in the pipeline does not resolve**
|
|
182
|
+
Paths are relative to the project root: create the markdown file under `jds/` and list it in `data/pipeline.md` as `local:jds/{filename}.md` (same spelling as the file name). See [jds/README.md](../jds/README.md) and [`modes/pipeline.md`](../modes/pipeline.md).
|
|
183
|
+
|
|
184
|
+
## Contributing
|
|
185
|
+
|
|
186
|
+
Pull requests and issue reports are welcome on `razroo/JobForge`. See [CONTRIBUTING.md](../CONTRIBUTING.md) for branch workflow, ideas (documentation, `examples/`, `templates/portals.example.yml`, dashboard features, utility scripts), and the checks maintainers expect before a PR (`npm run verify` and `npm run build:dashboard`). Contributors work against Path B (clone the harness directly).
|
package/docs/demo.gif
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|