job-forge 2.14.31 → 2.14.33

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.
@@ -17,7 +17,7 @@ same: produce the best final writing you can from the context you were given.
17
17
  - Write cover letters, Section G draft answers, "Why X?" responses.
18
18
  - Compose STAR+R interview stories and the story bank (`modes/offer.md` Block F).
19
19
  - Draft LinkedIn outreach messages (`modes/contact.md`).
20
- - Score offers using the Canonical Scoring Model — emit the JSON score block per `modes/_shared.md`, then the narrative report.
20
+ - Score offers using the Canonical Scoring Model — emit the JSON score block per `modes/_shared.md`, validate it with `job-forge score:check` when it drives PDF/apply/batch decisions, then write the narrative report.
21
21
  - Drive a single high-stakes application form only when the orchestrator explicitly dispatches you in `apply` mode. In that case, follow `modes/apply.md` exactly and use the same Geometra/Gmail flow as `@general-free`.
22
22
 
23
23
  ## Skip These Tasks
@@ -16,7 +16,7 @@ same: produce the best final writing you can from the context you were given.
16
16
  - Write cover letters, Section G draft answers, "Why X?" responses.
17
17
  - Compose STAR+R interview stories and the story bank (`modes/offer.md` Block F).
18
18
  - Draft LinkedIn outreach messages (`modes/contact.md`).
19
- - Score offers using the Canonical Scoring Model — emit the JSON score block per `modes/_shared.md`, then the narrative report.
19
+ - Score offers using the Canonical Scoring Model — emit the JSON score block per `modes/_shared.md`, validate it with `job-forge score:check` when it drives PDF/apply/batch decisions, then write the narrative report.
20
20
  - Drive a single high-stakes application form only when the orchestrator explicitly dispatches you in `apply` mode. In that case, follow `modes/apply.md` exactly and use the same Geometra/Gmail flow as `@general-free`.
21
21
 
22
22
  ## Skip These Tasks
@@ -24,13 +24,13 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
24
24
  - [H5] Re-dispatch the same company only AFTER the previous subagent returns. Never fire the same `task` twice while the first is still in flight.
25
25
  why: two in-flight subagents for the same URL race on Geometra sessions and on tracker TSV writes, corrupting state and sometimes double-submitting
26
26
 
27
- - [H5b] Do not use `task` to poll task status. If OpenCode returns a task/session id without a final result, record the id, stop dispatching new rounds, and tell the user the round is still in flight. When the user asks to check later, inspect authoritative files (`batch/tracker-additions/*.tsv`, `batch/tracker-additions/merged/*.tsv`, day files, `.jobforge-ledger/events.jsonl`, `.jobforge-index.json`, `.jobforge-facts.json`, or `iso-trace`) rather than spawning a "check task status" subagent.
27
+ - [H5b] Do not use `task` to poll task status. If OpenCode returns a task/session id without a final result, record the id, stop dispatching new rounds, and tell the user the round is still in flight. When the user asks to check later, inspect authoritative files (`batch/tracker-additions/*.tsv`, `batch/tracker-additions/merged/*.tsv`, day files, `.jobforge-ledger/events.jsonl`, `.jobforge-index.json`, `.jobforge-facts.json`, `.jobforge-timeline.json`, or `iso-trace`) rather than spawning a "check task status" subagent.
28
28
  why: OpenCode status prompts can be delivered into the target subagent as a new user message; a 2026-04-25 trace caused a subagent to call `task` recursively instead of finishing the application
29
29
 
30
30
  - [H6] Application outcomes flow through `batch/tracker-additions/*.tsv`, not `data/pipeline.md`. After any multi-apply run, the orchestrator MUST run `npx job-forge merge` then `npx job-forge verify` before ending the session.
31
31
  why: `pipeline.md` is the URL inbox (`[ ]` pending → `[x]` processed); `data/applications/YYYY-MM-DD.md` is the outcome log; the TSV pathway is the only safe bridge because `merge` handles column order and duplicate detection
32
32
 
33
- - [H7] Load-bearing facts passed to downstream subagents must originate from a file, not from prior subagent prose. Authoritative sources: `data/pipeline.md`, `data/scan-history.tsv`, `batch/scan-output-*.md`, `reports/{num}-*.md` with `**URL:**` / `**Score:**` headers, `batch/tracker-additions/*.tsv`, cached JD content returned by `npx job-forge cache:get --url ...`, source path/line pointers returned by `npx job-forge index:query ...`, and materialized fact records returned by `npx job-forge facts:query ...`.
33
+ - [H7] Load-bearing facts passed to downstream subagents must originate from a file, not from prior subagent prose. Authoritative sources: `data/pipeline.md`, `data/scan-history.tsv`, `batch/scan-output-*.md`, `reports/{num}-*.md` with `**URL:**` / `**Score:**` headers, emitted score JSON validated by `npx job-forge score:check --input ...`, `batch/tracker-additions/*.tsv`, cached JD content returned by `npx job-forge cache:get --url ...`, source path/line pointers returned by `npx job-forge index:query ...`, and materialized fact records returned by `npx job-forge facts:query ...`.
34
34
  why: 2026-04-18 scan subagent returned 30 fabricated Greenhouse IDs in prose (plausible-looking, non-existent); orchestrator dispatched 30 downstream subagents that all 404'd. Subagents can hallucinate IDs, scores, and confirmation text — round-trip through a file or don't trust the value
35
35
 
36
36
  - [H8] Never paste proxy values from `config/profile.yml` into `task` prompts, status text, or summaries. If a proxy is configured, tell the subagent exactly: "Proxy is configured; read `config/profile.yml` and pass its top-level `proxy:` object to every `geometra_connect` call." Do not transcribe `server`, `username`, `password`, or `bypass`, even if you just read them from disk.
@@ -95,16 +95,22 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
95
95
  - [D18] Treat `templates/redact.json` as the source of truth before exporting local traces, prompts, reports, or fixtures outside the project. Use `npx job-forge redact:scan --input <file>`, `redact:apply --input <file> --output .jobforge-redacted/<file>`, or `redact:verify --input <file>` instead of hand-redacting with prose. This complements H8; it does not make it acceptable to paste secrets into prompts.
96
96
  why: `iso-redact` is not an MCP and adds no prompt/tool-schema tokens; it gives deterministic safe-export checks whose findings do not print matched secret values
97
97
 
98
+ - [D19] Treat `templates/score.json` as the source of truth for offer scoring weights, bands, and gates. After emitting a report score JSON that will drive PDF/application/batch decisions, run `npx job-forge score:check --input <file>`; for apply decisions run `npx job-forge score:gate --input <file> --gate apply`. Do not recalculate weighted totals or thresholds manually when the local helper can check them.
99
+ why: `iso-score` is not an MCP and adds no prompt/tool-schema tokens; it makes scoring math, recommendation bands, and threshold booleans executable local policy instead of repeated model prose
100
+
101
+ - [D20] Treat `templates/timeline.json` as the source of truth for follow-up and next-action timing. For follow-up triage, run `npx job-forge timeline:due` before reading tracker files; use `npx job-forge timeline:check --fail-on overdue` when a workflow must fail only on stale actions. Use `timeline:build` when a durable `.jobforge-timeline.json` artifact is useful.
102
+ why: `iso-timeline` is not an MCP and adds no prompt/tool-schema tokens; it turns timing windows over tracker/pipeline sources into executable local policy instead of repeated date math in model context
103
+
98
104
  ## Procedure
99
105
 
100
106
  1. Check `cv.md`, `profile.yml`, and `portals.yml`; onboard if any file is missing.
101
107
  2. Pick and name the mode from **Routing** [D6]. No match → ask; do not guess.
102
- 3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use materialized facts when a fact query can answer the question [D13b]. Use canonical identity keys for duplicate checks [D15]. Use migration checks for harness drift [D14]. Use redaction checks before exporting local artifacts [D18]. Decide inline vs delegated work [D1].
108
+ 3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use materialized facts when a fact query can answer the question [D13b]. Use canonical identity keys for duplicate checks [D15]. Use score checks/gates for scoring decisions [D19]. Use timeline due/check commands for follow-up timing [D20]. Use migration checks for harness drift [D14]. Use redaction checks before exporting local artifacts [D18]. Decide inline vs delegated work [D1].
103
109
  4. Prepare Geometra dispatches: cleanup [H3], canon/index/facts/ledger prefilter when useful [D8, D13, D13b, D15], dedupe [H2], location filter [D5], materialize candidate facts/gates and run preflight plan/check [D16], routing [D2, D10], proxy prompt hygiene [H8].
104
110
  5. Dispatch at most 2 tasks per round [H1]; wait for final outcomes, not just task ids [H5b], then settle the round with postflight status [D17].
105
111
  6. Keep multi-job form-filling out of the orchestrator [H4].
106
112
  7. Cross-check subagent facts against authoritative files [H7].
107
- 8. Apply score gate [D4].
113
+ 8. Apply score gate [D4, D19].
108
114
  9. Merge contract-validated TSV outcomes [H6, D9].
109
115
  10. Verify tracker and run postflight check before ending [H6, D17].
110
116
 
@@ -32,7 +32,7 @@ same: produce the best final writing you can from the context you were given.
32
32
  - Write cover letters, Section G draft answers, "Why X?" responses.
33
33
  - Compose STAR+R interview stories and the story bank (`modes/offer.md` Block F).
34
34
  - Draft LinkedIn outreach messages (`modes/contact.md`).
35
- - Score offers using the Canonical Scoring Model — emit the JSON score block per `modes/_shared.md`, then the narrative report.
35
+ - Score offers using the Canonical Scoring Model — emit the JSON score block per `modes/_shared.md`, validate it with `job-forge score:check` when it drives PDF/apply/batch decisions, then write the narrative report.
36
36
  - Drive a single high-stakes application form only when the orchestrator explicitly dispatches you in `apply` mode. In that case, follow `modes/apply.md` exactly and use the same Geometra/Gmail flow as `@general-free`.
37
37
 
38
38
  ## Skip These Tasks
@@ -90,6 +90,10 @@ Postflight dispatch settlement (terminal, outside opencode):
90
90
  npx job-forge postflight:status --plan batch/preflight-plan.json --outcomes batch/postflight-outcomes.json
91
91
  npx job-forge postflight:check --plan batch/preflight-plan.json --outcomes batch/postflight-outcomes.json
92
92
 
93
+ Follow-up timeline (terminal, outside opencode):
94
+ npx job-forge timeline:due
95
+ npx job-forge timeline:check --fail-on overdue
96
+
93
97
  Consumer migrations (terminal, outside opencode):
94
98
  npx job-forge migrate:plan # preview package.json/.gitignore drift
95
99
  npx job-forge migrate:apply # apply safe harness upgrade migrations
@@ -99,6 +103,11 @@ Artifact contracts (terminal, outside opencode):
99
103
  npx iso-contract explain jobforge.tracker-row --contracts templates/contracts.json
100
104
  npx job-forge tracker-line ... --write # renders + validates tracker TSV locally
101
105
 
106
+ Score policy (terminal, outside opencode):
107
+ npx job-forge score:check --input /tmp/score.json
108
+ npx job-forge score:gate --input /tmp/score.json --gate apply
109
+ npx job-forge score:explain
110
+
102
111
  Role capabilities (terminal, outside opencode):
103
112
  npx job-forge capabilities:explain general-free
104
113
  npx job-forge capabilities:check general-free --tool browser --mcp geometra --filesystem write
@@ -207,6 +216,9 @@ Step 4 — Materialize and check the dispatch plan
207
216
  (or another explicit JSON file). Include source paths for company, role,
208
217
  companyRoleKey, URL, score, duplicate/location gates, and any skip/block
209
218
  decision.
219
+ - If the candidate came from a fresh evaluation score JSON, run npx job-forge
220
+ score:check --input <score.json> and npx job-forge score:gate --input
221
+ <score.json> --gate apply before using that score as an apply gate.
210
222
  - Run npx job-forge preflight:check --candidates <file> to fail on missing
211
223
  sources or blocked gates, then npx job-forge preflight:plan --candidates
212
224
  <file> --json > batch/preflight-plan.json to get the bounded round list.
package/AGENTS.md CHANGED
@@ -19,13 +19,13 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
19
19
  - [H5] Re-dispatch the same company only AFTER the previous subagent returns. Never fire the same `task` twice while the first is still in flight.
20
20
  why: two in-flight subagents for the same URL race on Geometra sessions and on tracker TSV writes, corrupting state and sometimes double-submitting
21
21
 
22
- - [H5b] Do not use `task` to poll task status. If OpenCode returns a task/session id without a final result, record the id, stop dispatching new rounds, and tell the user the round is still in flight. When the user asks to check later, inspect authoritative files (`batch/tracker-additions/*.tsv`, `batch/tracker-additions/merged/*.tsv`, day files, `.jobforge-ledger/events.jsonl`, `.jobforge-index.json`, `.jobforge-facts.json`, or `iso-trace`) rather than spawning a "check task status" subagent.
22
+ - [H5b] Do not use `task` to poll task status. If OpenCode returns a task/session id without a final result, record the id, stop dispatching new rounds, and tell the user the round is still in flight. When the user asks to check later, inspect authoritative files (`batch/tracker-additions/*.tsv`, `batch/tracker-additions/merged/*.tsv`, day files, `.jobforge-ledger/events.jsonl`, `.jobforge-index.json`, `.jobforge-facts.json`, `.jobforge-timeline.json`, or `iso-trace`) rather than spawning a "check task status" subagent.
23
23
  why: OpenCode status prompts can be delivered into the target subagent as a new user message; a 2026-04-25 trace caused a subagent to call `task` recursively instead of finishing the application
24
24
 
25
25
  - [H6] Application outcomes flow through `batch/tracker-additions/*.tsv`, not `data/pipeline.md`. After any multi-apply run, the orchestrator MUST run `npx job-forge merge` then `npx job-forge verify` before ending the session.
26
26
  why: `pipeline.md` is the URL inbox (`[ ]` pending → `[x]` processed); `data/applications/YYYY-MM-DD.md` is the outcome log; the TSV pathway is the only safe bridge because `merge` handles column order and duplicate detection
27
27
 
28
- - [H7] Load-bearing facts passed to downstream subagents must originate from a file, not from prior subagent prose. Authoritative sources: `data/pipeline.md`, `data/scan-history.tsv`, `batch/scan-output-*.md`, `reports/{num}-*.md` with `**URL:**` / `**Score:**` headers, `batch/tracker-additions/*.tsv`, cached JD content returned by `npx job-forge cache:get --url ...`, source path/line pointers returned by `npx job-forge index:query ...`, and materialized fact records returned by `npx job-forge facts:query ...`.
28
+ - [H7] Load-bearing facts passed to downstream subagents must originate from a file, not from prior subagent prose. Authoritative sources: `data/pipeline.md`, `data/scan-history.tsv`, `batch/scan-output-*.md`, `reports/{num}-*.md` with `**URL:**` / `**Score:**` headers, emitted score JSON validated by `npx job-forge score:check --input ...`, `batch/tracker-additions/*.tsv`, cached JD content returned by `npx job-forge cache:get --url ...`, source path/line pointers returned by `npx job-forge index:query ...`, and materialized fact records returned by `npx job-forge facts:query ...`.
29
29
  why: 2026-04-18 scan subagent returned 30 fabricated Greenhouse IDs in prose (plausible-looking, non-existent); orchestrator dispatched 30 downstream subagents that all 404'd. Subagents can hallucinate IDs, scores, and confirmation text — round-trip through a file or don't trust the value
30
30
 
31
31
  - [H8] Never paste proxy values from `config/profile.yml` into `task` prompts, status text, or summaries. If a proxy is configured, tell the subagent exactly: "Proxy is configured; read `config/profile.yml` and pass its top-level `proxy:` object to every `geometra_connect` call." Do not transcribe `server`, `username`, `password`, or `bypass`, even if you just read them from disk.
@@ -90,16 +90,22 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
90
90
  - [D18] Treat `templates/redact.json` as the source of truth before exporting local traces, prompts, reports, or fixtures outside the project. Use `npx job-forge redact:scan --input <file>`, `redact:apply --input <file> --output .jobforge-redacted/<file>`, or `redact:verify --input <file>` instead of hand-redacting with prose. This complements H8; it does not make it acceptable to paste secrets into prompts.
91
91
  why: `iso-redact` is not an MCP and adds no prompt/tool-schema tokens; it gives deterministic safe-export checks whose findings do not print matched secret values
92
92
 
93
+ - [D19] Treat `templates/score.json` as the source of truth for offer scoring weights, bands, and gates. After emitting a report score JSON that will drive PDF/application/batch decisions, run `npx job-forge score:check --input <file>`; for apply decisions run `npx job-forge score:gate --input <file> --gate apply`. Do not recalculate weighted totals or thresholds manually when the local helper can check them.
94
+ why: `iso-score` is not an MCP and adds no prompt/tool-schema tokens; it makes scoring math, recommendation bands, and threshold booleans executable local policy instead of repeated model prose
95
+
96
+ - [D20] Treat `templates/timeline.json` as the source of truth for follow-up and next-action timing. For follow-up triage, run `npx job-forge timeline:due` before reading tracker files; use `npx job-forge timeline:check --fail-on overdue` when a workflow must fail only on stale actions. Use `timeline:build` when a durable `.jobforge-timeline.json` artifact is useful.
97
+ why: `iso-timeline` is not an MCP and adds no prompt/tool-schema tokens; it turns timing windows over tracker/pipeline sources into executable local policy instead of repeated date math in model context
98
+
93
99
  ## Procedure
94
100
 
95
101
  1. Check `cv.md`, `profile.yml`, and `portals.yml`; onboard if any file is missing.
96
102
  2. Pick and name the mode from **Routing** [D6]. No match → ask; do not guess.
97
- 3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use materialized facts when a fact query can answer the question [D13b]. Use canonical identity keys for duplicate checks [D15]. Use migration checks for harness drift [D14]. Use redaction checks before exporting local artifacts [D18]. Decide inline vs delegated work [D1].
103
+ 3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use materialized facts when a fact query can answer the question [D13b]. Use canonical identity keys for duplicate checks [D15]. Use score checks/gates for scoring decisions [D19]. Use timeline due/check commands for follow-up timing [D20]. Use migration checks for harness drift [D14]. Use redaction checks before exporting local artifacts [D18]. Decide inline vs delegated work [D1].
98
104
  4. Prepare Geometra dispatches: cleanup [H3], canon/index/facts/ledger prefilter when useful [D8, D13, D13b, D15], dedupe [H2], location filter [D5], materialize candidate facts/gates and run preflight plan/check [D16], routing [D2, D10], proxy prompt hygiene [H8].
99
105
  5. Dispatch at most 2 tasks per round [H1]; wait for final outcomes, not just task ids [H5b], then settle the round with postflight status [D17].
100
106
  6. Keep multi-job form-filling out of the orchestrator [H4].
101
107
  7. Cross-check subagent facts against authoritative files [H7].
102
- 8. Apply score gate [D4].
108
+ 8. Apply score gate [D4, D19].
103
109
  9. Merge contract-validated TSV outcomes [H6, D9].
104
110
  10. Verify tracker and run postflight check before ending [H6, D17].
105
111
 
package/CLAUDE.md CHANGED
@@ -19,13 +19,13 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
19
19
  - [H5] Re-dispatch the same company only AFTER the previous subagent returns. Never fire the same `task` twice while the first is still in flight.
20
20
  why: two in-flight subagents for the same URL race on Geometra sessions and on tracker TSV writes, corrupting state and sometimes double-submitting
21
21
 
22
- - [H5b] Do not use `task` to poll task status. If OpenCode returns a task/session id without a final result, record the id, stop dispatching new rounds, and tell the user the round is still in flight. When the user asks to check later, inspect authoritative files (`batch/tracker-additions/*.tsv`, `batch/tracker-additions/merged/*.tsv`, day files, `.jobforge-ledger/events.jsonl`, `.jobforge-index.json`, `.jobforge-facts.json`, or `iso-trace`) rather than spawning a "check task status" subagent.
22
+ - [H5b] Do not use `task` to poll task status. If OpenCode returns a task/session id without a final result, record the id, stop dispatching new rounds, and tell the user the round is still in flight. When the user asks to check later, inspect authoritative files (`batch/tracker-additions/*.tsv`, `batch/tracker-additions/merged/*.tsv`, day files, `.jobforge-ledger/events.jsonl`, `.jobforge-index.json`, `.jobforge-facts.json`, `.jobforge-timeline.json`, or `iso-trace`) rather than spawning a "check task status" subagent.
23
23
  why: OpenCode status prompts can be delivered into the target subagent as a new user message; a 2026-04-25 trace caused a subagent to call `task` recursively instead of finishing the application
24
24
 
25
25
  - [H6] Application outcomes flow through `batch/tracker-additions/*.tsv`, not `data/pipeline.md`. After any multi-apply run, the orchestrator MUST run `npx job-forge merge` then `npx job-forge verify` before ending the session.
26
26
  why: `pipeline.md` is the URL inbox (`[ ]` pending → `[x]` processed); `data/applications/YYYY-MM-DD.md` is the outcome log; the TSV pathway is the only safe bridge because `merge` handles column order and duplicate detection
27
27
 
28
- - [H7] Load-bearing facts passed to downstream subagents must originate from a file, not from prior subagent prose. Authoritative sources: `data/pipeline.md`, `data/scan-history.tsv`, `batch/scan-output-*.md`, `reports/{num}-*.md` with `**URL:**` / `**Score:**` headers, `batch/tracker-additions/*.tsv`, cached JD content returned by `npx job-forge cache:get --url ...`, source path/line pointers returned by `npx job-forge index:query ...`, and materialized fact records returned by `npx job-forge facts:query ...`.
28
+ - [H7] Load-bearing facts passed to downstream subagents must originate from a file, not from prior subagent prose. Authoritative sources: `data/pipeline.md`, `data/scan-history.tsv`, `batch/scan-output-*.md`, `reports/{num}-*.md` with `**URL:**` / `**Score:**` headers, emitted score JSON validated by `npx job-forge score:check --input ...`, `batch/tracker-additions/*.tsv`, cached JD content returned by `npx job-forge cache:get --url ...`, source path/line pointers returned by `npx job-forge index:query ...`, and materialized fact records returned by `npx job-forge facts:query ...`.
29
29
  why: 2026-04-18 scan subagent returned 30 fabricated Greenhouse IDs in prose (plausible-looking, non-existent); orchestrator dispatched 30 downstream subagents that all 404'd. Subagents can hallucinate IDs, scores, and confirmation text — round-trip through a file or don't trust the value
30
30
 
31
31
  - [H8] Never paste proxy values from `config/profile.yml` into `task` prompts, status text, or summaries. If a proxy is configured, tell the subagent exactly: "Proxy is configured; read `config/profile.yml` and pass its top-level `proxy:` object to every `geometra_connect` call." Do not transcribe `server`, `username`, `password`, or `bypass`, even if you just read them from disk.
@@ -90,16 +90,22 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
90
90
  - [D18] Treat `templates/redact.json` as the source of truth before exporting local traces, prompts, reports, or fixtures outside the project. Use `npx job-forge redact:scan --input <file>`, `redact:apply --input <file> --output .jobforge-redacted/<file>`, or `redact:verify --input <file>` instead of hand-redacting with prose. This complements H8; it does not make it acceptable to paste secrets into prompts.
91
91
  why: `iso-redact` is not an MCP and adds no prompt/tool-schema tokens; it gives deterministic safe-export checks whose findings do not print matched secret values
92
92
 
93
+ - [D19] Treat `templates/score.json` as the source of truth for offer scoring weights, bands, and gates. After emitting a report score JSON that will drive PDF/application/batch decisions, run `npx job-forge score:check --input <file>`; for apply decisions run `npx job-forge score:gate --input <file> --gate apply`. Do not recalculate weighted totals or thresholds manually when the local helper can check them.
94
+ why: `iso-score` is not an MCP and adds no prompt/tool-schema tokens; it makes scoring math, recommendation bands, and threshold booleans executable local policy instead of repeated model prose
95
+
96
+ - [D20] Treat `templates/timeline.json` as the source of truth for follow-up and next-action timing. For follow-up triage, run `npx job-forge timeline:due` before reading tracker files; use `npx job-forge timeline:check --fail-on overdue` when a workflow must fail only on stale actions. Use `timeline:build` when a durable `.jobforge-timeline.json` artifact is useful.
97
+ why: `iso-timeline` is not an MCP and adds no prompt/tool-schema tokens; it turns timing windows over tracker/pipeline sources into executable local policy instead of repeated date math in model context
98
+
93
99
  ## Procedure
94
100
 
95
101
  1. Check `cv.md`, `profile.yml`, and `portals.yml`; onboard if any file is missing.
96
102
  2. Pick and name the mode from **Routing** [D6]. No match → ask; do not guess.
97
- 3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use materialized facts when a fact query can answer the question [D13b]. Use canonical identity keys for duplicate checks [D15]. Use migration checks for harness drift [D14]. Use redaction checks before exporting local artifacts [D18]. Decide inline vs delegated work [D1].
103
+ 3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use materialized facts when a fact query can answer the question [D13b]. Use canonical identity keys for duplicate checks [D15]. Use score checks/gates for scoring decisions [D19]. Use timeline due/check commands for follow-up timing [D20]. Use migration checks for harness drift [D14]. Use redaction checks before exporting local artifacts [D18]. Decide inline vs delegated work [D1].
98
104
  4. Prepare Geometra dispatches: cleanup [H3], canon/index/facts/ledger prefilter when useful [D8, D13, D13b, D15], dedupe [H2], location filter [D5], materialize candidate facts/gates and run preflight plan/check [D16], routing [D2, D10], proxy prompt hygiene [H8].
99
105
  5. Dispatch at most 2 tasks per round [H1]; wait for final outcomes, not just task ids [H5b], then settle the round with postflight status [D17].
100
106
  6. Keep multi-job form-filling out of the orchestrator [H4].
101
107
  7. Cross-check subagent facts against authoritative files [H7].
102
- 8. Apply score gate [D4].
108
+ 8. Apply score gate [D4, D19].
103
109
  9. Merge contract-validated TSV outcomes [H6, D9].
104
110
  10. Verify tracker and run postflight check before ending [H6, D17].
105
111
 
package/README.md CHANGED
@@ -31,7 +31,7 @@ The scaffolded `opencode.json` already has three MCPs wired up — they launch a
31
31
  - **Gmail** — reads replies from recruiters
32
32
  - **state-trace** — typed working memory for cross-session context (resumed batches, recent decisions, repeated portal quirks). Install once with `python3 -m pip install "state-trace[mcp]"`; the MCP command is `state-trace-mcp`.
33
33
 
34
- JobForge also keeps MCP-free local workflow state: `templates/canon.json` defines URL/company/role identity keys via `@razroo/iso-canon`, `templates/contracts.json` defines tracker/apply artifact shapes via `@razroo/iso-contract`, `templates/capabilities.json` defines role capability boundaries via `@razroo/iso-capabilities`, `templates/context.json` defines deterministic mode/reference bundles via `@razroo/iso-context`, `templates/preflight.json` defines safe dispatch rounds/gates via `@razroo/iso-preflight`, `templates/postflight.json` defines safe dispatch settlement via `@razroo/iso-postflight`, `templates/redact.json` defines safe-export redaction rules via `@razroo/iso-redact`, `templates/migrations.json` defines safe consumer-project upgrades via `@razroo/iso-migrate`, `templates/facts.json` defines source-backed fact extraction via `@razroo/iso-facts`, `.jobforge-ledger/events.jsonl` records duplicate/status events via `@razroo/iso-ledger`, `.jobforge-cache/` stores reusable JD/artifact content via `@razroo/iso-cache`, `.jobforge-index.json` indexes artifact source pointers via `@razroo/iso-index`, and `.jobforge-facts.json` materializes queryable facts with provenance. None of these add always-on prompt or tool-schema tokens.
34
+ JobForge also keeps MCP-free local workflow state and policy: `templates/canon.json` defines URL/company/role identity keys via `@razroo/iso-canon`, `templates/contracts.json` defines tracker/apply artifact shapes via `@razroo/iso-contract`, `templates/score.json` defines weighted scoring and gates via `@razroo/iso-score`, `templates/timeline.json` defines follow-up and next-action windows via `@razroo/iso-timeline`, `templates/capabilities.json` defines role capability boundaries via `@razroo/iso-capabilities`, `templates/context.json` defines deterministic mode/reference bundles via `@razroo/iso-context`, `templates/preflight.json` defines safe dispatch rounds/gates via `@razroo/iso-preflight`, `templates/postflight.json` defines safe dispatch settlement via `@razroo/iso-postflight`, `templates/redact.json` defines safe-export redaction rules via `@razroo/iso-redact`, `templates/migrations.json` defines safe consumer-project upgrades via `@razroo/iso-migrate`, `templates/facts.json` defines source-backed fact extraction via `@razroo/iso-facts`, `.jobforge-ledger/events.jsonl` records duplicate/status events via `@razroo/iso-ledger`, `.jobforge-cache/` stores reusable JD/artifact content via `@razroo/iso-cache`, `.jobforge-index.json` indexes artifact source pointers via `@razroo/iso-index`, `.jobforge-facts.json` materializes queryable facts with provenance, and `.jobforge-timeline.json` materializes due/overdue follow-up actions. None of these add always-on prompt or tool-schema tokens.
35
35
 
36
36
  `npm install` also materializes symlinks for every supported agent harness — OpenCode, Cursor, Claude Code, and Codex — so you can run `opencode`, `cursor`, `claude`, or `codex` in the same project and each picks up the shared MCP config and instructions.
37
37
 
@@ -63,11 +63,11 @@ JobForge turns opencode into a full job search command center. Instead of manual
63
63
  | Feature | Description |
64
64
  |---------|-------------|
65
65
  | **Auto-Pipeline** | Paste a URL, get a full evaluation + PDF + tracker entry |
66
- | **Unified Scoring** | 10 weighted dimensions, consistent across all modes, with calibration anchors |
66
+ | **Unified Scoring** | 10 weighted dimensions, consistent across all modes, with calibration anchors and deterministic `job-forge score:*` checks |
67
67
  | **Anti-AI-Detection CVs** | Writing rules that avoid ATS filters on Indeed, LinkedIn, Workday |
68
68
  | **6-Block Evaluation** | Role summary, CV match, level strategy, comp research, personalization, interview prep (STAR+R) |
69
69
  | **Interview Story Bank** | Curated bank of 10-12 stories with match counts, archetype tags, and automatic pruning |
70
- | **Follow-Up System** | Timing-based nudges: Applied 7+ days ago nudge, Interviewed 1 day ago thank-you note, email scanning via Gmail MCP |
70
+ | **Follow-Up System** | `job-forge timeline:*` computes timing-based nudges from local tracker/pipeline sources: Applied 7+ days ago, Contacted 5+ days ago, Interview 1-day thank-you, and 7-day interview nudge. |
71
71
  | **Gmail Integration** | MCP server configured to retrieve emails for interview callbacks, offer responses, and application status updates |
72
72
  | **Rejection Analysis** | Captures stage + reason, surfaces patterns (archetype gaps, scoring miscalibration) |
73
73
  | **Offer Negotiation** | Total comp breakdown, equity valuation, leverage from pipeline, counter-offer scripts |
@@ -78,7 +78,7 @@ JobForge turns opencode into a full job search command center. Instead of manual
78
78
  | **Durable Batch Orchestration** | `batch-runner.sh` uses `@razroo/iso-orchestrator` for resumable bundle execution, bounded fan-out, mutexed state writes, and workflow records in `.jobforge-runs/`. |
79
79
  | **Pipeline Integrity** | Automated merge, dedup, status normalization, health checks |
80
80
  | **Cost-Aware Agent Routing** | Three subagents (`@general-free`, `@general-paid`, `@glm-minimal`) with per-task tool surfaces. On OpenCode, JobForge pins all tiers to `opencode-go/deepseek-v4-flash` so application runs avoid overloaded free-model pools. See [Subagent Routing in AGENTS.md](AGENTS.md) for the task-to-agent mapping. |
81
- | **Trace + Telemetry + Guard + Contract + Canon + Ledger + Capabilities + Context + Cache + Index + Facts + Preflight + Postflight + Redact + Migrate** | `job-forge trace:*` exposes local OpenCode transcripts, `job-forge telemetry:*` summarizes runs, `job-forge guard:*` audits deterministic policy rules, `templates/contracts.json` enforces artifact shape with `iso-contract`, `job-forge canon:*` derives stable URL/company/role identity keys, `job-forge ledger:*` queries append-only workflow state, `job-forge capabilities:*` checks role boundaries, `job-forge context:*` plans mode/reference context bundles, `job-forge cache:*` reuses fetched JD/artifact content, `job-forge index:*` queries compact source pointers, `job-forge facts:*` materializes source-backed job/application/candidate facts, `job-forge preflight:*` plans bounded apply dispatch rounds from file-backed candidate facts, `job-forge postflight:*` settles dispatch outcomes/artifacts/post-steps, `job-forge redact:*` sanitizes local exports, and `job-forge migrate:*` applies safe consumer-project upgrades without MCP/tool-schema overhead. |
81
+ | **Trace + Telemetry + Guard + Contract + Score + Canon + Ledger + Capabilities + Context + Cache + Index + Facts + Timeline + Preflight + Postflight + Redact + Migrate** | `job-forge trace:*` exposes local OpenCode transcripts, `job-forge telemetry:*` summarizes runs, `job-forge guard:*` audits deterministic policy rules, `templates/contracts.json` enforces artifact shape with `iso-contract`, `job-forge score:*` computes/checks weighted offer scores, `job-forge canon:*` derives stable URL/company/role identity keys, `job-forge ledger:*` queries append-only workflow state, `job-forge capabilities:*` checks role boundaries, `job-forge context:*` plans mode/reference context bundles, `job-forge cache:*` reuses fetched JD/artifact content, `job-forge index:*` queries compact source pointers, `job-forge facts:*` materializes source-backed job/application/candidate facts, `job-forge timeline:*` computes due/overdue follow-up actions, `job-forge preflight:*` plans bounded apply dispatch rounds from file-backed candidate facts, `job-forge postflight:*` settles dispatch outcomes/artifacts/post-steps, `job-forge redact:*` sanitizes local exports, and `job-forge migrate:*` applies safe consumer-project upgrades without MCP/tool-schema overhead. |
82
82
  | **Token Cost Visibility** | `job-forge tokens --days 1` for per-session breakdown; `job-forge session-report --since-minutes 60 --log` to flag sessions over budget and append history to `data/token-usage.tsv`. Auto-logged after every batch run. |
83
83
 
84
84
  ## Usage
@@ -118,7 +118,7 @@ You paste a job URL or description
118
118
 
119
119
  ┌────────▼─────────┐
120
120
  │ A-F Evaluation │ Match, gaps, comp research, STAR stories
121
- │ (reads cv.md) │ Unified 10-dimension scoring model
121
+ │ (reads cv.md) │ Unified 10-dimension scoring model + iso-score checks
122
122
  └────────┬─────────┘
123
123
 
124
124
  ┌────┼────┐
@@ -149,6 +149,7 @@ my-search/
149
149
  ├── .jobforge-cache/ # content-addressed local JD/artifact cache (personal, gitignored)
150
150
  ├── .jobforge-index.json # deterministic artifact lookup index (generated, gitignored)
151
151
  ├── .jobforge-facts.json # deterministic fact set with provenance (generated, gitignored)
152
+ ├── .jobforge-timeline.json # deterministic follow-up action plan (generated, gitignored)
152
153
  ├── .jobforge-redacted/ # sanitized local exports (generated, gitignored)
153
154
  ├── reports/ # generated evaluation reports (personal, gitignored)
154
155
  ├── batch/{batch-input,batch-state}.tsv, tracker-additions/, logs/ # personal
@@ -166,7 +167,7 @@ my-search/
166
167
  ├── .opencode/skills/job-forge.md # → skill router
167
168
  ├── .opencode/agents/ # → @general-free, @general-paid, @glm-minimal
168
169
  ├── modes/ # → _shared.md + skill modes
169
- ├── templates/ # → states.yml, portals.example.yml, cv-template.html, canon.json, capabilities.json, context.json, index.json, facts.json, preflight.json, postflight.json, redact.json, migrations.json
170
+ ├── templates/ # → states.yml, portals.example.yml, cv-template.html, canon.json, score.json, timeline.json, capabilities.json, context.json, index.json, facts.json, preflight.json, postflight.json, redact.json, migrations.json
170
171
  ├── batch/batch-prompt.md # → batch worker prompt
171
172
  ├── batch/batch-runner.sh # → parallel orchestrator
172
173
 
@@ -192,7 +193,7 @@ JobForge/
192
193
  │ ├── sync.mjs # postinstall: creates symlinks in consumer project
193
194
  │ └── create-job-forge.mjs # scaffolder
194
195
  ├── modes/ # _shared.md + 16 skill modes
195
- ├── templates/ # cv-template.html, portals.example.yml, states.yml, canon.json, capabilities.json, context.json, facts.json, preflight.json, postflight.json, redact.json, migrations.json
196
+ ├── templates/ # cv-template.html, portals.example.yml, states.yml, canon.json, score.json, timeline.json, capabilities.json, context.json, facts.json, preflight.json, postflight.json, redact.json, migrations.json
196
197
  ├── config/profile.example.yml # template for consumer's profile.yml
197
198
  ├── batch/{batch-prompt.md,batch-runner.sh} # batch orchestrator
198
199
  ├── scripts/
@@ -204,6 +205,8 @@ JobForge/
204
205
  │ ├── cache.mjs # iso-cache-backed local artifact cache CLI
205
206
  │ ├── index.mjs # iso-index-backed artifact lookup CLI
206
207
  │ ├── facts.mjs # iso-facts-backed local fact materialization
208
+ │ ├── timeline.mjs # iso-timeline-backed follow-up planning CLI
209
+ │ ├── score.mjs # iso-score-backed offer scoring CLI
207
210
  │ ├── canon.mjs # iso-canon-backed identity normalization CLI
208
211
  │ ├── preflight.mjs # iso-preflight-backed dispatch planning CLI
209
212
  │ ├── postflight.mjs # iso-postflight-backed dispatch settlement CLI
package/bin/job-forge.mjs CHANGED
@@ -26,9 +26,11 @@
26
26
  * cache:* Reuse local deterministic artifacts via iso-cache
27
27
  * index:* Query local artifacts via iso-index
28
28
  * facts:* Materialize source-backed local facts via iso-facts
29
+ * score:* Compute/check deterministic offer scores via iso-score
29
30
  * canon:* Compute deterministic identity keys via iso-canon
30
31
  * preflight:* Plan safe dispatch rounds via iso-preflight
31
32
  * postflight:* Settle dispatch outcomes via iso-postflight
33
+ * timeline:* Plan follow-up/next-action windows via iso-timeline
32
34
  * redact:* Sanitize local exports via iso-redact
33
35
  * migrate:* Apply deterministic consumer-project migrations via iso-migrate
34
36
  * sync Re-run the harness symlink sync (bin/sync.mjs)
@@ -144,6 +146,16 @@ const factsAliases = {
144
146
  'facts:path': 'path',
145
147
  };
146
148
 
149
+ const scoreAliases = {
150
+ 'score:compute': 'compute',
151
+ 'score:verify': 'verify',
152
+ 'score:check': 'check',
153
+ 'score:gate': 'gate',
154
+ 'score:compare': 'compare',
155
+ 'score:explain': 'explain',
156
+ 'score:path': 'path',
157
+ };
158
+
147
159
  const canonAliases = {
148
160
  'canon:normalize': 'normalize',
149
161
  'canon:key': 'key',
@@ -166,6 +178,17 @@ const postflightAliases = {
166
178
  'postflight:path': 'path',
167
179
  };
168
180
 
181
+ const timelineAliases = {
182
+ 'timeline:status': 'status',
183
+ 'timeline:build': 'build',
184
+ 'timeline:plan': 'plan',
185
+ 'timeline:due': 'due',
186
+ 'timeline:check': 'check',
187
+ 'timeline:verify': 'verify',
188
+ 'timeline:explain': 'explain',
189
+ 'timeline:path': 'path',
190
+ };
191
+
169
192
  const redactAliases = {
170
193
  'redact:scan': 'scan',
171
194
  'redact:verify': 'verify',
@@ -238,6 +261,11 @@ Commands:
238
261
  facts:query Query materialized facts with source path/line provenance
239
262
  facts:verify Validate local fact set integrity
240
263
  facts:check Check configured fact requirements
264
+ score:compute Compute canonical weighted score from report score JSON
265
+ score:check Validate score math, thresholds, rationales, and dimensions
266
+ score:gate Evaluate one score gate (apply, pdf, draft_answers, strong)
267
+ score:compare Compare two score JSON files deterministically
268
+ score:explain Show the active scoring rubric from templates/score.json
241
269
  canon:key Print stable URL/company/role/company-role keys
242
270
  canon:compare Compare two identifiers as same/possible/different
243
271
  canon:explain Show the active identity canonicalization policy
@@ -247,6 +275,11 @@ Commands:
247
275
  postflight:status Reconcile dispatch plan, outcomes, artifacts, and post-steps
248
276
  postflight:check Fail unless a dispatched workflow is fully settled
249
277
  postflight:explain Show the active postflight workflow policy
278
+ timeline:status Show local follow-up/next-action timeline status
279
+ timeline:build Build .jobforge-timeline.json from tracker/pipeline sources
280
+ timeline:due Show currently due/overdue follow-up actions
281
+ timeline:check Fail on due/overdue timeline actions per policy
282
+ timeline:explain Show the active timeline policy
250
283
  redact:scan Scan local text for sensitive values before export
251
284
  redact:verify Fail if local text still contains sensitive values
252
285
  redact:apply Write a sanitized copy of local text
@@ -295,12 +328,16 @@ Pass --help after a command to see its own flags, e.g.:
295
328
  job-forge index:query "acme"
296
329
  job-forge facts:has --fact application.status --key "company-role:acme:staff-engineer"
297
330
  job-forge facts:query --fact job.url --tag report
331
+ job-forge score:check --input /tmp/score.json
332
+ job-forge score:gate --input /tmp/score.json --gate apply
298
333
  job-forge canon:key company-role --company "Acme, Inc." --role "Senior SWE - Remote US"
299
334
  job-forge canon:compare company "OpenAI, Inc." "Open AI"
300
335
  job-forge preflight:plan --candidates batch/preflight-candidates.json
301
336
  job-forge preflight:check --candidates batch/preflight-candidates.json
302
337
  job-forge postflight:status --plan batch/preflight-plan.json --outcomes batch/postflight-outcomes.json
303
338
  job-forge postflight:check --plan batch/preflight-plan.json --outcomes batch/postflight-outcomes.json
339
+ job-forge timeline:due
340
+ job-forge timeline:check --fail-on overdue
304
341
  job-forge redact:scan --input raw-session.jsonl
305
342
  job-forge redact:apply --input raw-session.jsonl --output .jobforge-redacted/session.jsonl
306
343
  job-forge migrate:check
@@ -449,6 +486,21 @@ if (cmd === 'facts' || factsAliases[cmd]) {
449
486
  process.exit(result.status ?? 1);
450
487
  }
451
488
 
489
+ if (cmd === 'score' || scoreAliases[cmd]) {
490
+ const scoreArgs = cmd === 'score'
491
+ ? (rest.length === 0 ? ['help'] : rest)
492
+ : [scoreAliases[cmd], ...rest];
493
+
494
+ const scriptPath = join(PKG_ROOT, 'scripts/score.mjs');
495
+ const result = spawnSync(process.execPath, [scriptPath, ...scoreArgs], {
496
+ stdio: 'inherit',
497
+ cwd: PROJECT_DIR,
498
+ env: process.env,
499
+ });
500
+
501
+ process.exit(result.status ?? 1);
502
+ }
503
+
452
504
  if (cmd === 'canon' || canonAliases[cmd]) {
453
505
  const canonArgs = cmd === 'canon'
454
506
  ? (rest.length === 0 ? ['help'] : rest)
@@ -494,6 +546,21 @@ if (cmd === 'postflight' || postflightAliases[cmd]) {
494
546
  process.exit(result.status ?? 1);
495
547
  }
496
548
 
549
+ if (cmd === 'timeline' || timelineAliases[cmd]) {
550
+ const timelineArgs = cmd === 'timeline'
551
+ ? (rest.length === 0 ? ['help'] : rest)
552
+ : [timelineAliases[cmd], ...rest];
553
+
554
+ const scriptPath = join(PKG_ROOT, 'scripts/timeline.mjs');
555
+ const result = spawnSync(process.execPath, [scriptPath, ...timelineArgs], {
556
+ stdio: 'inherit',
557
+ cwd: PROJECT_DIR,
558
+ env: process.env,
559
+ });
560
+
561
+ process.exit(result.status ?? 1);
562
+ }
563
+
497
564
  if (cmd === 'redact' || redactAliases[cmd]) {
498
565
  const redactArgs = cmd === 'redact'
499
566
  ? (rest.length === 0 ? ['help'] : rest)
@@ -32,7 +32,7 @@ my-search/
32
32
  ├── .opencode/skills/job-forge.md # → skill router
33
33
  ├── .opencode/agents/ # → @general-free, @general-paid, @glm-minimal
34
34
  ├── modes/ # → mode files
35
- ├── templates/ # → states.yml, portals.example.yml, cv-template.html, preflight.json, postflight.json
35
+ ├── templates/ # → states.yml, portals.example.yml, cv-template.html, score.json, timeline.json, preflight.json, postflight.json
36
36
  ├── batch/batch-prompt.md # → batch worker prompt
37
37
  ├── batch/batch-runner.sh # → parallel orchestrator
38
38
  └── node_modules/job-forge/ # harness, installed from npm
@@ -40,7 +40,7 @@ my-search/
40
40
 
41
41
  Symlinks are created by the harness's `postinstall` hook (`bin/sync.mjs`) on every `npm install`. Real files at those paths are preserved — if a user locally customizes a mode file, the sync skips that symlink and warns.
42
42
 
43
- The consumer's `opencode.json` loads a small set of stable files as always-present instructions: `AGENTS.harness.md` (harness operational rules), `templates/states.yml` (canonical application states), `modes/_shared.md` (scoring model), and `cv.md` (the candidate's CV). Caching these in the prefix means agents never Read them as tool calls. Churning content (score calibration anchors, specific mode files) stays out of `instructions` and is Read on demand.
43
+ The consumer's `opencode.json` loads a small set of stable files as always-present instructions: `AGENTS.harness.md` (harness operational rules), `templates/states.yml` (canonical application states), `modes/_shared.md` (scoring model), and `cv.md` (the candidate's CV). The executable scoring rubric lives in `templates/score.json` and is checked on demand with `job-forge score:*`, so agents do not need to repeat scoring math in the prompt. Caching stable prose in the prefix means agents never Read it as tool calls. Churning content (score calibration anchors, specific mode files) stays out of `instructions` and is Read on demand.
44
44
 
45
45
  The skill router (`.opencode/skills/job-forge.md`) loads mode and data files on demand, keeping per-session input tokens low (~20-40K for most modes instead of ~130-170K when everything was force-loaded).
46
46
 
@@ -122,7 +122,7 @@ For customization (archetypes, weights, tone), start with `_shared.md` and [CUST
122
122
  - D: Comp research (WebSearch).
123
123
  - E: CV personalization plan.
124
124
  - F: Interview prep (STAR stories).
125
- 5. **Score**: Weighted average across 10 dimensions (1-5)
125
+ 5. **Score**: Weighted average across 10 dimensions (1-5), computed and gated from `templates/score.json`
126
126
  6. **Report**: Save as `reports/{num}-{company}-{date}.md`
127
127
  7. **PDF**: Generate ATS-optimized CV (`generate-pdf.mjs`)
128
128
  8. **Track**: Write one TSV per evaluation under `batch/tracker-additions/` (see [AGENTS.md](../AGENTS.md) TSV layout); fold rows into `data/applications.md` with `npm run merge` / `merge-tracker.mjs` when you are ready (not automatic in every workflow)
@@ -163,11 +163,14 @@ data/pipeline.md → Pending URLs and `local:jds/...` inbox (see modes/p
163
163
  .jobforge-ledger/events.jsonl → Append-only workflow events for cheap local duplicate/status checks
164
164
  .jobforge-index.json → Deterministic artifact lookup index built from templates/index.json
165
165
  .jobforge-facts.json → Deterministic fact set built from templates/facts.json
166
+ .jobforge-timeline.json → Deterministic follow-up action plan built from templates/timeline.json
166
167
  jds/*.md → Saved job descriptions referenced from the pipeline (`local:jds/{file}`)
167
168
  templates/states.yml → Canonical status values
168
169
  templates/canon.json → Canonical URL/company/role identity keys
170
+ templates/score.json → Canonical weighted scoring rubric and gates
169
171
  templates/context.json → Deterministic mode/reference context bundle policy
170
172
  templates/facts.json → Source-backed fact extraction policy
173
+ templates/timeline.json → Follow-up and next-action timing policy
171
174
  templates/preflight.json → Safe apply dispatch rounds/gates policy
172
175
  templates/postflight.json → Safe apply dispatch settlement policy
173
176
  templates/migrations.json → Safe consumer-project upgrade policy
@@ -185,7 +188,10 @@ Create `data/pipeline.md` when you start using the URL inbox (`/job-forge pipeli
185
188
  - Ledger: `.jobforge-ledger/events.jsonl` (created by `job-forge ledger:rebuild`, `tracker-line --write`, or `merge`; gitignored personal state)
186
189
  - Index: `.jobforge-index.json` (created on demand by `job-forge index:*`; gitignored local lookup state)
187
190
  - Facts: `.jobforge-facts.json` (created on demand by `job-forge facts:*`; gitignored local fact state)
191
+ - Timeline: `.jobforge-timeline.json` (created on demand by `job-forge timeline:*`; gitignored local next-action state)
188
192
  - Canon: `templates/canon.json` (identity rules inspected with `job-forge canon:*`)
193
+ - Score: `templates/score.json` (weighted rubric and gates inspected with `job-forge score:*`)
194
+ - Timeline policy: `templates/timeline.json` (follow-up windows inspected with `job-forge timeline:*`)
189
195
  - Preflight: `templates/preflight.json` (dispatch rounds/gates inspected with `job-forge preflight:*`)
190
196
  - Postflight: `templates/postflight.json` (dispatch outcomes/artifacts/post-steps inspected with `job-forge postflight:*`)
191
197
  - Migrations: `templates/migrations.json` (applied by `job-forge sync` and inspectable with `job-forge migrate:*`)
@@ -194,7 +200,7 @@ Create `data/pipeline.md` when you start using the URL inbox (`/job-forge pipeli
194
200
 
195
201
  ## Pipeline Integrity
196
202
 
197
- From the project root, `npx job-forge verify` (or `npm run verify`) runs `verify-pipeline.mjs`. When a tracker file exists, it validates canonical statuses (using `templates/states.yml` when that file is present and parseable), validates every tracker row against `templates/contracts.json`, warns on probable duplicate company/role rows, checks that report column markdown links resolve to files in the repo, validates score column format (`X.X/5`, `N/A`, or `DUP`), rejects table rows with too few columns, flags markdown bold inside the score column, and warns if any `batch/tracker-additions/*.tsv` files are still waiting to be merged. If `.jobforge-ledger/events.jsonl` exists, verify also validates the append-only ledger. If `.jobforge-index.json` exists, verify validates the artifact index. If `.jobforge-facts.json` exists, verify validates the materialized fact set. It also compares state ids from `templates/states.yml` to an internal fallback list and warns when the two sets drift. **Fresh clone:** the command exits successfully when neither `data/applications.md` nor root `applications.md` exists yet; pending-TSV and states-drift checks still run so contributors see unmerged batch output early. Optional setup validation after you add `cv.md` and `config/profile.yml`: `npm run sync-check` (`cv-sync-check.mjs`).
203
+ From the project root, `npx job-forge verify` (or `npm run verify`) runs `verify-pipeline.mjs`. When a tracker file exists, it validates canonical statuses (using `templates/states.yml` when that file is present and parseable), validates every tracker row against `templates/contracts.json`, warns on probable duplicate company/role rows, checks that report column markdown links resolve to files in the repo, validates score column format (`X.X/5`, `N/A`, or `DUP`), rejects table rows with too few columns, flags markdown bold inside the score column, and warns if any `batch/tracker-additions/*.tsv` files are still waiting to be merged. If `.jobforge-ledger/events.jsonl` exists, verify also validates the append-only ledger. If `.jobforge-index.json` exists, verify validates the artifact index. If `.jobforge-facts.json` exists, verify validates the materialized fact set. If `.jobforge-timeline.json` exists, verify validates the follow-up timeline. It also compares state ids from `templates/states.yml` to an internal fallback list and warns when the two sets drift. **Fresh clone:** the command exits successfully when neither `data/applications.md` nor root `applications.md` exists yet; pending-TSV and states-drift checks still run so contributors see unmerged batch output early. Optional setup validation after you add `cv.md` and `config/profile.yml`: `npm run sync-check` (`cv-sync-check.mjs`).
198
204
 
199
205
  **`verify-pipeline.mjs` checks (same order as the script header):**
200
206
 
@@ -210,8 +216,9 @@ From the project root, `npx job-forge verify` (or `npm run verify`) runs `verify
210
216
  10. Validate `.jobforge-ledger/events.jsonl` when present.
211
217
  11. Validate `.jobforge-index.json` when present.
212
218
  12. Validate `.jobforge-facts.json` when present.
219
+ 13. Validate `.jobforge-timeline.json` when present.
213
220
 
214
- When the tracker file is missing, checks 1-6 and 8 are skipped; checks 7, 9, 10, and 11 still run when applicable.
221
+ When the tracker file is missing, checks 1-6 and 8 are skipped; checks 7, 9, 10, 11, 12, and 13 still run when applicable.
215
222
 
216
223
  ## Contributing touchpoints
217
224
 
@@ -236,6 +243,8 @@ Scripts maintain data consistency. In a consumer project they're invoked via the
236
243
  | `scripts/ledger.mjs` | `npx job-forge ledger:status` / `ledger:has` / `ledger:rebuild` | Deterministic `@razroo/iso-ledger` state over tracker, TSV, and pipeline files |
237
244
  | `scripts/index.mjs` | `npx job-forge index:status` / `index:has` / `index:query` | Deterministic `@razroo/iso-index` lookup over reports, tracker rows, TSVs, pipeline, scan history, and ledger events |
238
245
  | `scripts/facts.mjs` | `npx job-forge facts:status` / `facts:has` / `facts:query` | Deterministic `@razroo/iso-facts` materialization over job URLs, scores, application statuses, preflight candidates, scan history, and ledger events |
246
+ | `scripts/timeline.mjs` | `npx job-forge timeline:due` / `timeline:check` / `timeline:build` | Deterministic `@razroo/iso-timeline` follow-up and next-action planning over tracker rows and dated pipeline items |
247
+ | `scripts/score.mjs` | `npx job-forge score:check` / `score:gate` / `score:explain` | Deterministic `@razroo/iso-score` checks for weighted offer scores, threshold booleans, recommendations, and score gates |
239
248
  | `scripts/canon.mjs` | `npx job-forge canon:normalize` / `canon:key` / `canon:compare` | Deterministic `@razroo/iso-canon` identity normalization for URLs, companies, roles, and company+role pairs |
240
249
  | `scripts/context.mjs` | `npx job-forge context:list` / `context:plan` / `context:check` / `context:render` | Deterministic `@razroo/iso-context` mode/reference context bundle planning and rendering |
241
250
  | `scripts/preflight.mjs` | `npx job-forge preflight:plan` / `preflight:check` / `preflight:explain` | Deterministic `@razroo/iso-preflight` dispatch planning for file-backed candidate facts and gates |
@@ -158,6 +158,14 @@ Artifact lookup policy lives in `templates/index.json` and is built locally by `
158
158
 
159
159
  Fact extraction policy lives in `templates/facts.json` and is built locally by `@razroo/iso-facts`. Use `job-forge facts:query --fact job.url`, `job-forge facts:has --fact application.status --key "company-role:acme:staff-engineer"`, and `job-forge facts:verify` to work with compact source-backed facts instead of rereading reports, tracker day files, TSVs, candidate JSON, scan history, and ledger events. Query, has, verify, and check rebuild `.jobforge-facts.json` on demand, so scaffolded projects need no setup. JobForge canonicalizes company/role and URL fact keys through `templates/canon.json` before writing the fact set. This is not an MCP and does not add prompt or tool-schema tokens.
160
160
 
161
+ ## JobForge timeline policy
162
+
163
+ Follow-up and next-action policy lives in `templates/timeline.json` and is planned locally by `@razroo/iso-timeline`. Use `job-forge timeline:due` to list due/overdue nudges, `job-forge timeline:check --fail-on overdue` to fail only when action is stale, and `job-forge timeline:build` to materialize `.jobforge-timeline-events.jsonl` plus `.jobforge-timeline.json` for inspection. It reads tracker rows and dated pipeline items from local files, so scaffolded projects need no setup. This is not an MCP and does not add prompt or tool-schema tokens.
164
+
165
+ ## JobForge scoring policy
166
+
167
+ Weighted scoring policy lives in `templates/score.json` and is enforced locally by `@razroo/iso-score`. Use `job-forge score:check --input <score.json>` to validate emitted report score JSON, `job-forge score:gate --input <score.json> --gate apply` to check an application threshold, and `job-forge score:explain` to inspect the active dimensions, weights, bands, and gates. Custom forks can change weights or thresholds in `templates/score.json`, but keep the dimension ids aligned with `modes/_shared.md` and report rendering.
168
+
161
169
  ## JobForge identity canonicalization
162
170
 
163
171
  URL, company, role, and company+role identity rules live in `templates/canon.json` and are enforced locally by `@razroo/iso-canon`. Use `job-forge canon:key company-role --company "OpenAI, Inc." --role "Senior SWE, AI Platform"` to derive the same duplicate key used by ledger/index helpers, and `job-forge canon:compare company "OpenAI, Inc." "Open AI"` to explain whether two values resolve to the same entity. Custom forks can extend aliases, suffixes, stop words, and match thresholds in `templates/canon.json`. This is not an MCP and does not add prompt or tool-schema tokens.
package/docs/README.md CHANGED
@@ -31,7 +31,7 @@ The harness exposes a single CLI (`job-forge`) installed as a `bin` entry. In a
31
31
 
32
32
  | What you need | Where to read |
33
33
  |---------------|---------------|
34
- | Full command list (`verify`, `merge`, `dedup`, `normalize`, `pdf`, `sync-check`, `tokens`, `trace`, `telemetry`, `guard`, `ledger`, `canon`, `context`, `index`, `facts`, `preflight`, `postflight`, `redact`, `sync`). | [SETUP.md — Tracker and scripts (terminal)](SETUP.md#tracker-and-scripts-terminal). |
34
+ | Full command list (`verify`, `merge`, `dedup`, `normalize`, `pdf`, `sync-check`, `tokens`, `trace`, `telemetry`, `guard`, `ledger`, `canon`, `context`, `index`, `facts`, `timeline`, `preflight`, `postflight`, `redact`, `sync`). | [SETUP.md — Tracker and scripts (terminal)](SETUP.md#tracker-and-scripts-terminal). |
35
35
  | What each harness `.mjs` script does. | [ARCHITECTURE.md — Pipeline integrity](ARCHITECTURE.md#pipeline-integrity) and the scripts table underneath. |
36
36
  | Batch runner, TSV layout, and `batch/tracker-additions/` merge flow. | [batch/README.md](../batch/README.md). |
37
37
  | PR gate for harness contributions (`npm run verify` + `npm run build:dashboard`). | [CONTRIBUTING.md — Development](../CONTRIBUTING.md#development). |
package/docs/SETUP.md CHANGED
@@ -126,6 +126,8 @@ From your project root, these commands maintain the tracker and pipeline checks.
126
126
  | Pipeline health check | `npx job-forge verify` | `npm run verify` |
127
127
  | Merge `batch/tracker-additions/*.tsv` into the tracker | `npx job-forge merge` | `npm run merge` |
128
128
  | Inspect tracker row contract | `npx iso-contract explain jobforge.tracker-row --contracts templates/contracts.json` | _(none)_ |
129
+ | Validate emitted score JSON | `npx job-forge score:check --input /tmp/score.json` | `npm run score:check -- --input /tmp/score.json` |
130
+ | Check application score gate | `npx job-forge score:gate --input /tmp/score.json --gate apply` | `npm run score:gate -- --input /tmp/score.json --gate apply` |
129
131
  | Derive canonical company/role key | `npx job-forge canon:key company-role --company "Acme" --role "Staff Engineer"` | `npm run canon:key -- company-role --company ...` |
130
132
  | Compare identity values | `npx job-forge canon:compare company "OpenAI, Inc." "Open AI"` | `npm run canon:compare -- company ...` |
131
133
  | Inspect role capabilities | `npx job-forge capabilities:explain general-free` | `npm run capabilities:explain -- general-free` |
@@ -133,6 +135,8 @@ From your project root, these commands maintain the tracker and pipeline checks.
133
135
  | Inspect local JD/artifact cache | `npx job-forge cache:status` | `npm run cache:status` |
134
136
  | Inspect local artifact index | `npx job-forge index:status` | `npm run index:status` |
135
137
  | Inspect local materialized facts | `npx job-forge facts:status` | `npm run facts:status` |
138
+ | Show due follow-up actions | `npx job-forge timeline:due` | `npm run timeline:due` |
139
+ | Fail on stale follow-up actions | `npx job-forge timeline:check --fail-on overdue` | `npm run timeline:check -- --fail-on overdue` |
136
140
  | Plan safe application dispatch rounds | `npx job-forge preflight:plan --candidates batch/preflight-candidates.json` | `npm run preflight:plan -- --candidates ...` |
137
141
  | Fail on blocked preflight candidates | `npx job-forge preflight:check --candidates batch/preflight-candidates.json` | `npm run preflight:check -- --candidates ...` |
138
142
  | Settle dispatch outcomes after a round | `npx job-forge postflight:status --plan batch/preflight-plan.json --outcomes batch/postflight-outcomes.json` | `npm run postflight:status -- --plan ... --outcomes ...` |
@@ -159,6 +163,7 @@ From your project root, these commands maintain the tracker and pipeline checks.
159
163
  | Check/reuse cached JD content | `npx job-forge cache:has --url <url>` / `npx job-forge cache:get --url <url>` | `npm run cache:has -- --url ...` |
160
164
  | Query local artifact pointers | `npx job-forge index:query "Acme"` / `npx job-forge index:has --key company-role:acme:staff-engineer` | `npm run index:query -- Acme` |
161
165
  | Query local source-backed facts | `npx job-forge facts:query --fact job.url` / `npx job-forge facts:has --fact application.status --key company-role:acme:staff-engineer` | `npm run facts:query -- --fact job.url` |
166
+ | Materialize follow-up timeline | `npx job-forge timeline:build` | `npm run timeline:build` |
162
167
  | Apply safe consumer migrations | `npx job-forge migrate:apply` | `npm run migrate:apply` |
163
168
  | Re-create harness symlinks | `npx job-forge sync` | `npm run sync` |
164
169
  | Build optional dashboard TUI (Go on `PATH`) | `(cd node_modules/job-forge/dashboard && go build .)` | `npm run build:dashboard` (harness repo only) |
@@ -39,7 +39,7 @@ same: produce the best final writing you can from the context you were given.
39
39
  - Write cover letters, Section G draft answers, "Why X?" responses.
40
40
  - Compose STAR+R interview stories and the story bank (`modes/offer.md` Block F).
41
41
  - Draft LinkedIn outreach messages (`modes/contact.md`).
42
- - Score offers using the Canonical Scoring Model — emit the JSON score block per `modes/_shared.md`, then the narrative report.
42
+ - Score offers using the Canonical Scoring Model — emit the JSON score block per `modes/_shared.md`, validate it with `job-forge score:check` when it drives PDF/apply/batch decisions, then write the narrative report.
43
43
  - Drive a single high-stakes application form only when the orchestrator explicitly dispatches you in `apply` mode. In that case, follow `modes/apply.md` exactly and use the same Geometra/Gmail flow as `@general-free`.
44
44
 
45
45
  ## Skip These Tasks