{"id":"e58b340f-6d68-47cf-95a3-81ac6b2e9b8f","entityType":"agent","slug":"clawhub-bwancoding-jd-triage","name":"JD - Triage","canonicalUrl":"https://www.xpersona.co/agent/clawhub-bwancoding-jd-triage","canonicalPath":"/agent/clawhub-bwancoding-jd-triage","generatedAt":"2026-10-11T14:13:06.175Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T11:15:45.112Z","emptyReason":null},"description":"Scores a job posting on two independent dimensions — how much you want it (five weighted axes against your own criteria) and how likely you are to get it (your skills vs its stated requirements) — then returns one action. Any market, language, or profession.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s17fej7x2x0thkvnqzpvzkakh1872tj1:jd-triage","sourceUrl":"https://clawhub.ai/bwancoding/jd-triage","homepage":"https://clawhub.ai/bwancoding/skills/jd-triage","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/bwancoding/jd-triage","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/bwancoding/skills/jd-triage","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"JD - Triage technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T11:15:45.112Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T11:15:45.112Z","emptyReason":null},"stars":null,"forks":null,"downloads":1079,"packageName":null,"latestVersion":"1.1.1","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T11:15:45.045Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T11:15:45.112Z","lastCrawledAt":"2026-10-11T11:15:45.045Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T11:15:45.045Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.1","createdAt":"2026-07-27T03:22:23.293Z","changelog":"Fixes a language leak: a non-English posting in a non-English conversation came back with its verdict and headings in English. The screen now takes the reader's language including the tier; the English token stays in jd_history.md where history and compare parse it. No schema or scoring change.","fileCount":13,"zipByteSize":33036},{"version":"1.1.0","createdAt":"2026-07-25T18:19:45.334Z","changelog":"**Expanded to a 2D career decision system: want (desirability) vs can-get (candidacy).** - Separates evaluation into \"desirability\" (want) based on stored criteria and \"candidacy\" (match to requirements), never collapsing both into one score. - Adds weighted, customizable axes for desirability scoring, clearer rationale for scores, and explicit requirement matching for candidacy. - Enables advanced commands: skills-gap analysis, planning, comparison, and history analysis via new reference commands. - Refines language logic: always default to English, but fully support user language for output; never auto-translate stored content or quotes. - Overhauls state management, quickstart flow, schema migration, and history logging to support new features and reliability.","fileCount":13,"zipByteSize":32605}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17fej7x2x0thkvnqzpvzkakh1872tj1:jd-triage","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17fej7x2x0thkvnqzpvzkakh1872tj1:jd-triage` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/bwancoding/jd-triage before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T14:13:06.170Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-bwancoding-jd-triage/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T11:15:45.112Z","emptyReason":null},"readme":"Skill: JD - Triage\n\nOwner: bwancoding\n\nSummary: Scores a job posting on two independent dimensions — how much you want it (five weighted axes against your own criteria) and how likely you are to get it (your skills vs its stated requirements) — then returns one action. Any market, language, or profession.\n\nTags: latest:1.1.1\n\nVersion history:\n\nv1.1.1 | 2026-07-27T03:22:23.293Z | user\n\nFixes a language leak: a non-English posting in a non-English conversation came back with its verdict and headings in English. The screen now takes the reader's language including the tier; the English token stays in jd_history.md where history and compare parse it. No schema or scoring change.\n\nv1.1.0 | 2026-07-25T18:19:45.334Z | user\n\n**Expanded to a 2D career decision system: want (desirability) vs can-get (candidacy).**\n\n- Separates evaluation into \"desirability\" (want) based on stored criteria and \"candidacy\" (match to requirements), never collapsing both into one score.\n- Adds weighted, customizable axes for desirability scoring, clearer rationale for scores, and explicit requirement matching for candidacy.\n- Enables advanced commands: skills-gap analysis, planning, comparison, and history analysis via new reference commands.\n- Refines language logic: always default to English, but fully support user language for output; never auto-translate stored content or quotes.\n- Overhauls state management, quickstart flow, schema migration, and history logging to support new features and reliability.\n\nArchive index:\n\nArchive v1.1.1: 13 files, 33036 bytes\n\nFiles: _meta.json (128b), assets/criteria-template.yaml (8678b), assets/presets/knowledge-work.yaml (1245b), assets/presets/people-lead.yaml (1308b), assets/presets/tech-ic.yaml (1245b), README.md (5369b), references/analysis-commands.md (4902b), references/bootstrap.md (8282b), references/history.md (4812b), references/intensity-signals.md (4632b), references/scoring.md (8786b), skill-card.md (2746b), SKILL.md (16876b)\n\nFile v1.1.1:SKILL.md\n\n---\nname: jd-triage\ndescription: \"Career decision system for job seekers. Scores a job description on two independent dimensions — how much you want it (5 weighted axes against your stored criteria) and how likely you are to get it (your skills vs the JD's stated requirements) — then returns one concrete action. Use when (1) the user pastes a job description or recruiter message, (2) the user invokes /jd-triage or asks 'should I apply for this role', (3) the user asks to list, compare, or analyze previously evaluated roles, (4) the user asks what to learn next for a target role, (5) the user asks to set up, update, or reset their career criteria. Market-, language-, and profession-neutral; bootstraps a criteria profile on first run.\"\n---\n\n# jd-triage · v1.1.1\n\nA JD is evaluated on **two independent dimensions**, never collapsed into one number:\n\n- **Desirability** — do you want this? Five weighted axes scored against the user's stored criteria.\n- **Candidacy** — can you get this? The JD's stated must-have requirements vs the user's skills inventory.\n\nA role you want but can't get is a *stretch*, not a *skip*. A role you can get but don't want is a *backup*, not an *apply*. Collapsing both into one star rating destroys that distinction — which is the whole decision.\n\nResponsibilities:\n\n1. **Bootstrap & maintain** a criteria profile at `~/.openclaw/workspace/jd_criteria.md`.\n2. **Evaluate** a JD → two-dimension verdict + one action.\n3. **Log** every evaluation to `~/.openclaw/workspace/jd_history.md`.\n4. **Analyze / Plan** over accumulated history (see `references/analysis-commands.md`).\n\n## Language\n\n**Default to English.** If the user writes in another language, respond entirely in that language for the rest of the session.\n\n| Surface | Language |\n|---|---|\n| All conversational output — bootstrap Q&A, verdicts, tables, **and the verdict tier as displayed** | User's language (English by default) |\n| `jd_criteria.md` field keys, `jd_history.md` structural labels, verdict tier names **in storage** | **Always English** — grep-friendly, stable across language switches |\n| Stored free-text values (org names, summaries, red-line rationales, JD quotes) | The language the user wrote them in, at write time |\n\n**Never auto-translate stored content.** When listing or comparing entries written in different languages, render structural labels in the current language and show stored free text verbatim. Quotes pulled from a JD keep the JD's original language even when the surrounding output is translated — a translated quote is no longer evidence.\n\n## State machine\n\nOn every invocation, read `~/.openclaw/workspace/jd_criteria.md` and branch:\n\n| State | Condition | Action |\n|---|---|---|\n| **S1: Missing** | File does not exist | **Quick Start** (5 questions) → proceed to the requested command |\n| **S2: Schema gap** | File exists, `schema_version` < 3 | Migrate silently where possible, ask only for fields that cannot be inferred (see `references/bootstrap.md § Migration`) |\n| **S3: Fresh** | Complete, `last_updated` ≤ 30 days ago | Proceed directly. Note \"Using criteria from `<date>`\" in one line |\n| **S4: Stale** | Complete, `last_updated` > 30 days ago | Ask once: \"Anything changed — comp, location, red lines, what you're learning? (y/n)\". `n` → refresh timestamp only. `y` → user names the fields, patch those |\n| **S5: Explicit update** | \"update criteria\" / `/jd-triage update` / `/jd-triage reset` | Full bootstrap, current values pre-filled |\n\n`criteria_version` increments on every S1 / S2 / S5 write. S4 \"nothing changed\" bumps `last_updated` only.\n\nIf the invocation included a JD, continue to Evaluation after the criteria are settled. Otherwise execute the requested command and stop.\n\n## Commands\n\n| Input | Action |\n|---|---|\n| A pasted JD, or `/jd-triage` | Evaluate |\n| `/jd-triage update` \\| `reset` | S5 bootstrap |\n| `/jd-triage quickstart` | Force the 5-question Quick Start |\n| `/jd-triage learn` | Derive criteria from example JDs (`references/bootstrap.md § Derive from examples`) |\n| `/jd-triage history` | Last 10 entries, one line each |\n| `/jd-triage compare <id1> [<id2>]` | Side-by-side table |\n| `/jd-triage analyze` | Market signals across history → `references/analysis-commands.md` |\n| `/jd-triage plan` | Skill-gap plan per target role → `references/analysis-commands.md` |\n\nA past role referred to by org name resolves to an ID by grepping `jd_history.md`.\n\n## Evaluation\n\n### 1. Parse\n\nExtract: title, org name, responsibilities, **must-have requirements**, **preferred requirements** (keep these separate — the split drives Candidacy), comp, location and remote policy, intensity signals, reporting line, team size.\n\nIf the input has a title but no responsibilities or requirements, **stop and ask for the full posting.** Do not evaluate a title.\n\n### 2. Hard gates\n\nFailures produce **❌ OUT** and stop — except red lines, which are weighted (below).\n\n- `comp_floor` — compare like for like: the JD's basis (base / total / hourly) against the floor's basis, in the same currency and period. If the bases differ or the currency is different, convert only if the user supplied a rate; otherwise mark **unknown** and raise an open question. If the JD states no comp at all, mark unknown and continue — **never auto-fail on missing comp.**\n- `locations` / `remote_ok` — JD location must be in the list, or the JD must be remote-eligible under the user's `remote_ok` setting.\n- `intensity_tier` — the JD's implied tier must not exceed the user's. Signal patterns are per-language in `references/intensity-signals.md`. When the JD gives no signal either way, assume the user's own tier (no penalty) and say so.\n- `red_lines` — match **semantically**, not by substring. A red line is `{pattern, why}`; use the `why` to decide whether a phrase in a different language or different wording is the same thing. Then weight by position:\n\n  | Where the matched responsibility sits | Verdict |\n  |---|---|\n  | In the title, in the first 1–2 responsibility bullets, or plausibly >30% of the role | **❌ OUT** — core |\n  | Only in tail bullets, framed as support/assist/partner-with | **⚠️ CONDITIONAL** — score normally, flag it, raise an open question |\n  | Only in the requirements/preferred section, not in the duties | Note as an open question, do not gate |\n\n  Always cite the matched phrase **and its location** (\"bullet 6 of 7, framed as 'support'\"). A bare keyword is not a citation — the user needs the framing to judge.\n\n  Semantic matching cuts both ways: it must not fire on incidental use. A red line of \"growth\" does not match \"growth mindset\" in a values paragraph. State what you matched and let the user correct you.\n\n### 3. Desirability — 5 weighted axes\n\nScore each 1–5 per `references/scoring.md`. Weights come from `axis_weights` in the criteria file (defaults there too).\n\n| Axis | Scored against | Default weight |\n|---|---|---|\n| **Role fit** | `target_title_keywords`, seniority and scope of the role | 25% |\n| **Domain fit** | `target_domains` — what the org actually does | 20% |\n| **Org fit** | `org_traits` — user-described traits with their own weights | 15% |\n| **Vibe fit** | `vibe_anchors_positive` / `_negative`, each carrying a `why` | 25% |\n| **Comp fit** | `comp_floor` and `profile.current_comp` | 15% |\n\n**Never pad.** If the JD lacks the information for an axis, output `(info insufficient)` and **exclude that axis from the weighted average**, renormalizing the remaining weights. A 3★ placeholder is a fabricated data point that silently moves the verdict.\n\n**Vibe must cite.** Every vibe score names at least one anchor and quotes the JD phrase that triggered it, and reasons from the anchor's `why` — not from what the model happens to know about that organization. Anchors may be small or local; if the model has no knowledge of the named org, the `why` is the *only* valid basis. Adjective-only judgments (\"feels corporate\") are forbidden.\n\n### 4. Candidacy — can you get it?\n\nIf `skills` is empty — the normal state after Quick Start — ask for it once,\ninline, before scoring: *\"To score whether you can get this, I need your skills:\nwhat could you be interviewed on today, and what are you actively learning?\"*\nSave the answer so this is never asked twice.\n\nCompare the JD's **must-have** requirements against `skills` and `profile`:\n\n- Each requirement scores `1.0` if it matches `skills.mastered`, `0.5` if it matches `skills.learning`, `0` otherwise.\n- Years-of-experience counts as one requirement; met if `profile.years_of_experience` is within one year of the stated minimum.\n- **Preferred / nice-to-have requirements are excluded from the denominator** and reported separately.\n- Hit rate → tier: **Likely** ≥75%, **Plausible** 40–74%, **Stretch** <40%.\n- Fewer than 3 stated must-haves → **Unknown**; do not guess, raise an open question instead.\n\nDo not invent requirements the JD does not state. Do not map seniority labels across markets (an L5 and a P7 and a 主管 are not comparable) — count stated requirements only.\n\nReport gaps honestly in both directions: no inflation (\"you basically have this\"), no catastrophizing. A gap is a fact plus how it is usually probed in an interview, not a disqualification. Items in `skills.learning` are real partial credit — say so.\n\n### 5. Decide\n\nApply in this order. **The first rule that fires wins; stop there.**\n\n1. Hard gate failed → **❌ OUT**\n2. Red line in a non-core responsibility, **or** an unknown that could flip the verdict (comp, location, or scope) → **⚠️ CONDITIONAL**\n\n   Test whether the unknown can actually flip anything before invoking this. An\n   unknown that is already bounded on the deciding side is an **open question, not\n   a conditional**: a posting quoting €95,000 base against a €90,000 *total* floor\n   leaves comp unscoreable, but the gate is settled — base alone cannot make the\n   total fall below the floor. Say so and carry on to the matrix. Reserve\n   CONDITIONAL for unknowns whose resolution genuinely changes the answer.\n3. Otherwise → look up the matrix\n\nDesirability tier from the weighted average — checked top to bottom, **first\nmatch wins**, so a high average with one collapsed axis falls through rather than\nqualifying:\n\n- **Strong** — ≥ 4.0 and no axis ≤ 2\n- **Good** — ≥ 3.2 and no axis = 1\n- **Weak** — ≥ 2.4\n- **Poor** — < 2.4\n\nOne override: **vibe ≤ 2★ caps desirability at Weak**, whatever the average says. Vibe is the axis people rationalize away and regret.\n\n| | Likely | Plausible | Stretch |\n|---|---|---|---|\n| **Strong** | 🔥 Apply now | 🔥 Apply now | 🎯 Stretch apply |\n| **Good** | ✅ Apply | ✅ Apply | 🎯 Stretch apply |\n| **Weak** | 🗄️ Backup | 🗄️ Backup | ❌ Skip |\n| **Poor** | ❌ Skip | ❌ Skip | ❌ Skip |\n\nCandidacy **Unknown** → read the **Plausible** column, mark the result provisional\n(`✅ Apply (provisional)`), and put a question about the actual requirements first\nunder Open questions. Never silently drop to a one-dimensional verdict.\n\nDesirability **too thin to score** (three or more axes insufficient, per\n`references/scoring.md`) → the verdict is **⚠️ CONDITIONAL**, written as\n`Desirability: (too thin to score)`. There is no tier to report and no matrix to\nread; what the posting is missing goes under Open questions.\n\n### 6. Log\n\nAppend to `~/.openclaw/workspace/jd_history.md` — format and ID scheme in `references/history.md`. Create the file if missing.\n\n**The evaluation is not complete until this write succeeds.** Confirm it on the last line of the output (`Logged: JD-…`). If the write fails, say so explicitly — never let it fail silently.\n\n### 7. Output\n\nTwo surfaces, two rules. Do not let the second one leak into the first.\n\n**On screen — the user's language.** Everything in the template below is a\n*label*, not a literal: the section headings, the axis names, and the tier itself\nare all translated into the language of the conversation. Keep the **shape** —\nline order, star glyphs, arrows, emoji, the `<k>/<n>` figures. An evaluation\nwritten for a Chinese speaker reads in Chinese throughout; the only fragments\nthat stay in another language are quotes lifted from the posting, which are\nevidence and are never translated.\n\n**In `jd_history.md` — always English.** The stored `Action` field carries the\ntier token exactly as spelled here, in this casing, because `history` and\n`compare` parse it:\n\n`Apply now` · `Apply` · `Stretch apply` · `Backup` · `Skip` · `OUT` · `CONDITIONAL`\n\nNever store the action wording in place of the tier: a conditional evaluation\nstores `CONDITIONAL`, not `Confirm before applying`. What the reader saw on\nscreen may match neither string — it was that tier, in their language.\n\nIf the criteria were reused rather than collected, put `Using criteria from <date>`\non its own line **above** the verdict line, never below or inside it — translated\nlike everything else on screen.\n\n```\n<emoji> <TIER>          Desirability: <tier>   Candidacy: <tier>\n\nWant it\n  Role fit     ★★★★☆\n  Domain       ★★★★★\n  Org          ★★★☆☆\n  Vibe         ★★☆☆☆   anchor \"<name>\" — \"<JD phrase>\"\n  Comp         ★★★★☆\n  → weighted <n.n>/5\n\nCan get it\n  Meets <k>/<n> stated must-haves\n  ✅ <met>            ⚠️ <partial — in progress>            ❌ <gap>\n\n<one sentence: the actual judgment>\n\nOpen questions\n- <only real unknowns; omit the section entirely if none>\n\nLogged: JD-YYYYMMDD-NNN\n```\n\n**CONDITIONAL** — same shape, but the one-liner must carry the conditional explicitly: *\"Fits if `<X>` is confirmed; OUT if `<X>` turns out to be core.\"* Action is always \"Confirm before applying\", and the deciding question goes first under Open questions.\n\n**OUT** — short form, but never empty-handed:\n\n```\n❌ OUT\nTriggered: <gate or red line, with location and exact phrase>\n<one sentence: why>\n\nMatched anyway\n- <aligned dimensions worth remembering — omit if genuinely none>\n\nLogged: JD-YYYYMMDD-NNN\n```\n\nThe \"Matched anyway\" block exists so that rejections still accumulate signal about what to look for.\n\n## Behavioral constraints\n\n- **OUT means OUT.** Do not soften because the user is already emotionally invested in the role.\n- **Never pad a score.** Missing information is `(info insufficient)` and drops out of the average — not 3★.\n- **Never pre-fill from training data.** Criteria values come only from the user. Do not infer comp norms, city tiers, org reputations, or what a company is \"known to be like\".\n- **Reason from the user's `why`, not from fame.** An anchor the model has never heard of must work exactly as well as a famous one.\n- **Red lines are weighted, not literal**, and semantic, not substring.\n- **The output template is a shape, not a script.** Its English wording stands in\n  for the user's language — headings, axis names and the tier itself are all\n  translated. Only two things resist translation: values stored in\n  `jd_history.md`, and quotes taken from the posting.\n- **Keep the two dimensions apart.** Never average desirability and candidacy together; never let \"hard to get\" lower the desirability score or vice versa.\n- **Open questions are output, not internal state.** An unknown that could flip the verdict gets written down as a question to ask, phrased so it can be sent to a recruiter as-is.\n- **One JD at a time.** Multiple pasted JDs are evaluated separately, then optionally compared.\n- **No hollow encouragement.** No \"good luck\", no \"hope this helps\".\n- **Trust hand edits.** If the user edited `jd_criteria.md`, parse what is there. If a field is malformed, quote the line and ask — never silently overwrite.\n- **Analyze and plan need real data.** Below the thresholds in `references/analysis-commands.md`, say so and stop.\n\n## Detection triggers\n\n- A pasted block that reads like a job posting: a title-like line plus responsibilities or requirements. Length alone is not a trigger — do not claim any long paste.\n- `/jd-triage` and its subcommands.\n- \"should I apply\", \"is this role worth it\", \"evaluate this JD\", \"what should I learn next\", \"what patterns do you see in the roles I've looked at\", and their equivalents in the user's language.\n\n## Files\n\n| File | Loaded when |\n|---|---|\n| `assets/criteria-template.yaml` | Writing the criteria file |\n| `assets/presets/*.yaml` | Quick Start, to pre-fill structure |\n| `references/bootstrap.md` | S1 / S2 / S5, or `/jd-triage learn` |\n| `references/scoring.md` | Every evaluation |\n| `references/intensity-signals.md` | Intensity gate, when the JD is not in English |\n| `references/history.md` | Logging, `history`, `compare` |\n| `references/analysis-commands.md` | `analyze`, `plan` |\n\nLoad a reference only when its flow runs.\n\nFile v1.1.1:README.md\n\n# jd-triage\n\n**Two questions, kept apart: do you want it, and can you get it?**\n\nPaste a job posting. Get a verdict against the criteria *you* defined — plus an\nhonest read on whether you'd clear the bar. Most JD filters collapse both into\none score, which is exactly the information you needed.\n\nA skill for [OpenClaw](https://github.com/openclaw). Works in any market, any\nlanguage, any profession.\n\n---\n\n## What it does\n\n- **Scores two independent dimensions.** Desirability from five weighted axes\n  against your stored criteria; Candidacy from the posting's stated must-haves\n  against your skills. A role you want but can't get is a **stretch**, not a\n  skip. A role you can get but don't want is a **backup**, not an apply.\n- **Weights red lines by where they appear.** \"Owns revenue targets\" in the title\n  is an instant no. The same phrase in the last bullet, framed as *support*, is a\n  question to ask the recruiter — not a rejection.\n- **Makes vibe judgments inspectable.** Every vibe rating quotes the posting and\n  names the anchor it reasoned from. Anchors carry your *reason*, so the skill\n  works on a 12-person studio nobody has heard of, not just famous logos.\n- **Turns unknowns into questions.** Missing comp, ambiguous scope, unclear\n  remote policy — each becomes a line you can paste into a reply to the recruiter.\n- **Logs everything, including rejections.** Over time, `analyze` shows which\n  patterns keep reaching you and which requirement you keep almost meeting.\n\n## Starting up\n\nFive questions. Not thirteen.\n\nQuick Start asks for your role family and market, what titles you want, your\nfloors (comp with basis, locations, remote), your automatic no's, and one to\nthree organizations you admire *with a line on why each*. That is enough to\nevaluate. Everything else is asked once, at the moment it first matters.\n\nPrefer showing over telling? `/jd-triage learn` reads a handful of postings you\nliked and a handful you passed on, then proposes your red lines and anchors for\nyou to accept or edit.\n\n## Commands\n\n| Command | What it does |\n|---|---|\n| Paste a posting, or `/jd-triage` | Evaluate |\n| `/jd-triage quickstart` | The 5-question setup |\n| `/jd-triage learn` | Derive criteria from example postings |\n| `/jd-triage update` \\| `reset` | Edit criteria, current values pre-filled |\n| `/jd-triage history [apply\\|out]` | Last 10 evaluations |\n| `/jd-triage compare <id1> [<id2>]` | Side by side |\n| `/jd-triage analyze` | Patterns across everything you've evaluated (needs 8+) |\n| `/jd-triage plan` | Which gap to close next, ranked by what postings actually ask for |\n\nNatural language works too, in your language: \"should I apply to this\",\n\"和上次对比\", \"what should I learn next\".\n\n## Sample output\n\n```\n🎯 STRETCH APPLY        Desirability: Strong   Candidacy: Stretch\n\nWant it\n  Role fit     ★★★★★\n  Domain       ★★★★★\n  Org          ★★★★☆\n  Vibe         ★★★★☆   anchor \"Basecamp\" — why: \"small team, no growth theater\"\n                       triggered by: \"we ship deliberately\", \"no on-call\"\n  Comp         — (info insufficient)\n  → weighted 4.6/5 across 4 axes\n\nCan get it\n  Meets 2/5 stated must-haves\n  ✅ SQL   ✅ experiment design\n  ⚠️ Kubernetes (learning — half credit)\n  ❌ 5 years managing a team   ❌ regulated-industry experience\n\nStrong on everything you control; the management requirement is the one real\nblocker, and it's the kind they usually probe rather than verify.\n\nOpen questions\n- Is the team-management requirement firm, or would mentoring experience clear it?\n- What's the full package, and is the posted number base or all-in?\n\nLogged: JD-20260725-001\n```\n\n## Files it writes\n\n- `~/.openclaw/workspace/jd_criteria.md` — your criteria\n- `~/.openclaw/workspace/jd_history.md` — append-only evaluation log\n\nPlain markdown, hand-editable. The skill parses your edits and asks about\nanything malformed instead of overwriting it.\n\n## Privacy\n\nHistory stores verdicts, scores, and a one-line summary — **not the raw posting**.\nSet `history_detail: full` to keep raw text; you'll be warned once. Recruiter\ncontact details and unposted comp live in those postings, so don't turn it on for\na workspace you sync publicly.\n\n## Limitations\n\n- **It does not read your resume.** Candidacy is scored from the skills inventory\n  you provide, against what the posting actually states. It will not tell you how\n  you compare to other applicants.\n- **It does not map seniority across markets.** L5, P7, and Grade 6 are not\n  comparable, so it counts stated requirements and ignores the level label.\n- **Vibe is only as good as your anchors' reasons.** The `why` is what it reasons\n  from. One-word anchors produce weak ratings — that is the design working, not\n  failing.\n- **The sample is your inbox.** `analyze` describes the roles reaching you, never\n  \"the market\".\n- **No comp negotiation advice.** Out of scope.\n- **Model support is measured, not assumed.** Verified on GLM-5.2 and Claude\n  Sonnet 4.6 — 18 test cases, 100% verdict stability across repeated runs and\n  100% compliance with the skill's own rules. Smaller models are simply untested;\n  no claim either way.\n\n## Author\n\nBarry Wang ([@bwancoding](https://github.com/bwancoding)) —\n[github.com/bwancoding/jd-triage](https://github.com/bwancoding/jd-triage)\n\nMIT licensed.\n\nFile v1.1.1:_meta.json\n\n{\n  \"ownerId\": \"kn7fsvwdsd1ktv3vdfztehe7mx821jdh\",\n  \"slug\": \"jd-triage\",\n  \"version\": \"1.1.1\",\n  \"publishedAt\": 1785122543293\n}\n\nFile v1.1.1:references/analysis-commands.md\n\n# Analyze & Plan\n\nBoth commands read accumulated history. Both refuse to run on too little data —\na trend drawn from four postings is a horoscope.\n\n| Command | Needs | Below that |\n|---|---|---|\n| `/jd-triage analyze` | ≥ 8 entries in `jd_history.md` | Say how many exist and how many more are needed. Do not produce a partial report |\n| `/jd-triage plan` | `skills` and at least one `target_roles` entry | Point at `/jd-triage update`. If history has ≥ 8 entries, use it to rank gaps; otherwise say the ranking is based on the role description alone |\n\n**Report only what is in the data.** Empty category → \"none yet\". Never fill a\nsection by inference.\n\n---\n\n## `/jd-triage analyze`\n\nRead every entry plus the criteria file.\n\n```\n📊 <N> roles evaluated, <first date> → <last date>\n\nWhere they came from\n  <org trait>: <n>          ← grouped by the user's own org_traits vocabulary\n  <org trait>: <n>\n  unclassified: <n>\n\nTitles that keep appearing\n  <title pattern>: <n>\n\nWhat they ask for\n  <requirement>: <n>/<N> postings — you have it (mastered)\n  <requirement>: <n>/<N> postings — you're learning it       ← highest ROI\n  <requirement>: <n>/<N> postings — gap\n\nRed lines\n  \"<pattern>\": fired <n>× — <k> OUT, <m> CONDITIONAL\n\nYour two dimensions\n  Desirability: <n> Strong · <n> Good · <n> Weak · <n> Poor\n  Candidacy:    <n> Likely · <n> Plausible · <n> Stretch\n  Both high: <n>   ← the roles actually worth your time\n\nOutcomes (of <n> entries with Outcome filled)\n  <action tier>: applied <n>, interviewing <n>, rejected <n>, offer <n>\n\n💡 <2-4 observations, each traceable to a number above>\n```\n\n### Rules\n\n- **Group by the user's own vocabulary.** Bucket organizations using their\n  `org_traits`, not a taxonomy of your own. Anything that fits none is\n  `unclassified` — a large unclassified count is itself the finding, and means\n  their trait list is missing something.\n- **Requirement demand** is counted from stored requirement text across entries,\n  cross-referenced with `skills`. Rank by `frequency × (1 − credit)`: something\n  asked for constantly that the user is halfway through learning outranks\n  something rarer they have not started.\n- **Red-line review.** If a red line has fired ≥ 3 times and *never* produced an\n  OUT — only CONDITIONAL — say so and offer to demote it to a negative vibe\n  anchor. It is behaving like a preference, not a gate.\n  If a red line has never fired at all across ≥ 15 entries, mention it once;\n  it may be aimed at postings the user is not even seeing.\n- **Calibration, only with outcomes.** If ≥ 5 entries have an `Outcome`, compare\n  predicted Candidacy against what happened. Report it flatly:\n  *\"Of 6 rated Stretch, 3 got a first interview — the Candidacy read may be\n  running pessimistic.\"* Fewer than 5 → skip the section entirely, do not hedge\n  a guess.\n- **Never infer market conditions.** The sample is the user's inbox, not the job\n  market. Say \"the roles reaching you\", never \"the market is\".\n\n---\n\n## `/jd-triage plan`\n\nPer target role:\n\n```\n🎯 <role name>\n   Based on <n> matching postings in your history\n\nRequirements this role asks for\n   ✅ <requirement>            you have it — <n>/<N> postings asked\n   ⚠️ <requirement>            learning — <n>/<N> asked\n   ❌ <requirement>            gap — <n>/<N> asked\n\nNext, in order\n   1. <item> — asked in <n>/<N> postings, you're already partway\n   2. <item> — asked in <n>/<N>, not started\n   3. <item> — rarer, but blocks the roles you rated highest\n\nEvidence to build\n   <item>: <one concrete artifact that would let you claim it in an interview>\n```\n\n### Ranking\n\nOrder by demand × proximity: frequency in matching postings, weighted up for\nitems already in `skills.learning` (finishing beats starting), weighted down for\nitems appearing only in `preferred` sections.\n\nSay plainly when an item is low-frequency but appears in the highest-desirability\npostings — that is a different kind of bet and the user should make it knowingly.\n\n### Evidence suggestions\n\nOne per gap, concrete and checkable — something that produces an artifact a\nrecruiter or interviewer can look at. A shipped thing, a written thing, a\nmeasured thing. Never suggest a course as the artifact; a certificate is not\nevidence of the skill.\n\n### What this command does not do\n\n- **No timelines.** Do not estimate months to close a gap. You do not know the\n  user's available hours, and a fabricated schedule is worse than none. If they\n  ask, ask how much time per week they actually have and reason from that.\n- **No aptitude judgments.** Rank by market demand and proximity, never by\n  whether the user seems capable of something.\n- **No scope creep into career advice.** This command closes named gaps against\n  named roles. Whether the target role is the right target is a different\n  conversation, and it belongs to the user.\n\nFile v1.1.1:references/bootstrap.md\n\n# Bootstrap\n\nThree ways in. Default to **Quick Start** — a profile that exists is worth more\nthan a perfect profile the user abandoned halfway through.\n\n| Mode | When | Cost |\n|---|---|---|\n| **Quick Start** | S1 (no file), `/jd-triage quickstart` | 5 questions |\n| **Derive from examples** | `/jd-triage learn`, or offered when a profile is thin | Paste a few JDs |\n| **Full** | S5 (`update` / `reset`), or user asks | All fields |\n\nWrite to `~/.openclaw/workspace/jd_criteria.md` using `assets/criteria-template.yaml`.\nField keys English; values in the user's language.\n\n## Using presets\n\n`assets/presets/*.yaml` are **menus, never defaults**. Pick the preset matching\nthe user's `role_family`, show the suggested traits and red-line starters as a\nnumbered list, and write only the lines the user selects — reworded however they\nlike. Never silently write a preset value. `axis_weights` are the one exception:\nthey are a starting distribution, applied unless the user changes them, and\nmentioned once so the user knows they exist.\n\n---\n\n## Quick Start — 5 questions\n\nAsk one at a time. Accept \"skip\" on any of them.\n\n**1. Context.** \"What kind of role, what market, and which languages can you work\nin?\" → `context.role_family`, `context.market`, `context.languages`.\nFrom the market, infer `context.comp_convention` and **state the inference for\nconfirmation** (\"I'll assume comp is quoted as an all-in annual number — correct?\").\n\n**2. Target.** \"What titles are you looking for, and what should the organization\nactually do?\" → `soft_axes.target_title_keywords`, `soft_axes.target_domains`.\n\n**3. Floors.** \"What's the lowest offer you'd accept — and is that base or\nall-in? Where can you work, and is remote acceptable?\" → `hard_gates.comp_floor`\n(amount, currency, period, basis), `hard_gates.locations`, `hard_gates.remote_ok`.\n\n**4. Automatic no's.** \"Anything that makes a role an instant no — and why?\"\n→ `hard_gates.red_lines`. Push for the *why* on each one; it is what makes\nmatching work across languages and rewordings. \"None\" is a valid answer.\n\n**5. Anchors.** Use the preset's `vibe_prompt`. Ask for 1–3 organizations, teams,\nor products the user admires, **each with one line on why**.\n→ `soft_axes.vibe_anchors_positive`.\n\nThen write the file and say plainly what is not yet filled:\n\n> Saved. Org fit and Candidacy will show *info insufficient* until you add org\n> traits and your skills — I'll ask for those the first time they matter.\n\n### Just-in-time capture\n\nDo not front-load the rest. Ask for a field the first time an evaluation\nactually needs it, once, inline:\n\n- **Skills** — before scoring Candidacy for the first time: \"To score whether you\n  can get this, I need your skills. List what you could be interviewed on today,\n  and separately what you're actively learning.\" → `skills.mastered`,\n  `skills.learning`. Write them to the file so this is asked only once.\n- **Org traits** — the first time a JD's org type looks decision-relevant.\n- **Negative anchors** — the first time a JD trips something the user reacts badly\n  to: \"Want me to save that as a negative anchor?\"\n- **Intensity tier** — the first time a JD carries strong intensity signals.\n\nEach capture writes to the file and bumps `criteria_version`.\n\n---\n\n## Derive from examples (`/jd-triage learn`)\n\nThe highest-quality path, and the repair path for a thin or lazy profile. People\nare bad at stating preferences in the abstract and good at reacting to concrete\npostings.\n\n1. Ask for **2–4 postings the user would apply to** and **2–4 they turned down or\n   scrolled past**. Past rejections work; so do screenshots pasted as text.\n2. Read all of them and extract:\n   - Recurring title and scope patterns → `target_title_keywords`\n   - What the organizations do → `target_domains`\n   - Traits shared by the liked set / by the rejected set → `org_traits`\n   - Phrases that plausibly explain each rejection → candidate `red_lines`\n   - Tone and values language distinguishing the two sets → candidate anchors\n3. **Propose, never write.** Output a numbered list of drafted entries, each with\n   the evidence it came from and a drafted `why`:\n\n   ```\n   3. Red line: \"individual revenue target\"\n      From: Posting B, \"own a quarterly booking number\" — you skipped this one.\n      Why (draft): a quota changes what the job optimizes for.\n      Keep / edit / drop?\n   ```\n4. Write only accepted items. Ask the user to fix any `why` that does not sound\n   like them — the `why` is what the skill reasons from later.\n\nNever infer a red line from a single posting without saying which one it came\nfrom. One rejection can have many causes; the user picks the real one.\n\n---\n\n## Full bootstrap\n\nEvery field in `assets/criteria-template.yaml`, in four blocks, one block per\nturn. Pre-fill current values on S5 so the user only changes what moved.\n\n**Block 1 — Context & profile**\n`context` (role_family, market, languages, comp_convention, fx_rates if the user\ncompares currencies) · `profile` (years_of_experience, current_title_org,\ncurrent_comp with basis and notes)\n\n**Block 2 — Hard gates**\n`comp_floor` (with basis) · `locations` · `remote_ok` · `intensity_tier` ·\n`red_lines` (each with a `why`)\n\n**Block 3 — Soft axes**\n`target_title_keywords` · `target_domains` · `org_traits` (trait + weight 1–5) ·\n`vibe_anchors_positive` and `vibe_anchors_negative` (each with a `why`) ·\n`axis_weights` (offer the current distribution, ask only if they want to change it)\n\n**Block 4 — Skills & targets**\n`skills.mastered` / `.learning` / `.want_to_learn` · `target_roles`\n\nState the half-credit rule when asking for skills: `learning` items score 0.5\nagainst a requirement, so an honest split produces better advice than an\noptimistic one.\n\n### Summary and confirm\n\nShow everything grouped as above, then:\n\n```\nConfirm and save?  (y / edit <field>)\n```\n\n`edit <field>` re-asks that field only, then re-shows the summary. On `y`, write\nthe file with today's ISO date and an incremented `criteria_version`.\n\n---\n\n## Migration\n\nTriggered by S2 (`schema_version` < 3). Migrate everything inferable **without\nasking**, then ask only for what cannot be derived. Show a summary of what\nchanged before writing.\n\n| Old (v1 / v2) | New (v3) | How |\n|---|---|---|\n| `hard_gates.salary_floor` (string) | `hard_gates.comp_floor` (structured) | Parse amount / currency / period. **Basis cannot be inferred — ask.** Show the parse for confirmation |\n| `profile.current_salary` (string) | `profile.current_comp` (structured) | Same; keep anything unparseable in `notes` verbatim |\n| `lifestyle_tier` | `intensity_tier` | `strict_9to5`→`strict_hours`, `standard`→`standard`, `crunch`→`high`, `always_on`→`always_on` |\n| `target_cities` | `hard_gates.locations` | Copy. If `Remote` was in the list, set `remote_ok: yes` and drop it from locations |\n| `target_industries` | `soft_axes.target_domains` | Copy. Flag entries that describe an org *type* rather than a domain and offer to move them to `org_traits` |\n| `company_type_preferences` + `company_size_preferences` | `soft_axes.org_traits` | Each entry rated ≠ 3 becomes `{trait, weight}`. **Entries rated 3 are dropped** — they never changed any outcome. Say how many were dropped |\n| `hard_red_lines` (strings) | `hard_gates.red_lines` (`{pattern, why}`) | Pattern copies over; **`why` must be asked** — it is what enables semantic matching |\n| `vibe_anchors_positive` / `_negative` (strings) | same keys, `{name, why}` | Names copy over; **`why` must be asked.** Without it the skill can only reason from what it happens to know about that organization, which is exactly the failure mode v3 fixes |\n| `skills`, `target_roles`, `learning_velocity` (v2 only) | unchanged | Copy verbatim |\n| — | `context` | **Ask** — nothing in v1/v2 implies market or comp convention |\n| — | `axis_weights` | Apply defaults, mention once |\n\nSo a migration asks for, at most: comp basis, one `why` per red line and anchor,\nand the `context` block. Batch them into a single turn.\n\nIf `red_lines` is empty after migration, say so directly — it means the\nresponsibility-weighting logic has never had anything to act on — and offer\n`/jd-triage learn` to populate it from real postings.\n\nFile v1.1.1:references/history.md\n\n# History\n\n`~/.openclaw/workspace/jd_history.md` — a single append-only log. Create it on the first\nevaluation.\n\n**Every evaluation writes an entry, including OUT.** Rejections are the most\nuseful rows in the file: they are what `analyze` reads to tell the user which\npattern keeps landing in their inbox. An evaluation that produced no entry did\nnot finish — say so rather than letting it pass.\n\n## Language\n\nStructural labels are **always English** (`Evaluated`, `Action`, `Desirability`,\n`Candidacy`, `Scores`, `Summary`, `Triggered`, `Outcome`, `Criteria version`) so\nthe file stays greppable when the user switches languages.\n\nFree text — org name, title, summary, red-line citations, JD quotes — is stored\nin the language it was written in and **never retroactively translated**. Listing\nand comparison output renders labels in the current language and shows stored\ntext verbatim.\n\n## ID\n\n`JD-YYYYMMDD-NNN` — today's date, then a per-day sequence starting at `001`,\nfound by grepping existing entries with the same date prefix.\n\n## Entry — standard detail\n\n```markdown\n## [JD-20260725-001] <org> — <title>\n\n**Evaluated**: 2026-07-25\n**Criteria version**: 4\n**Action**: ✅ Apply\n**Desirability**: Good (3.6/5)\n**Candidacy**: Plausible (70%)\n\n### Scores\n- Role fit:  ★★★★☆\n- Domain:    ★★★★★\n- Org:       — (info insufficient)\n- Vibe:      ★★★☆☆\n- Comp:      ★★★★☆\n\n### Candidacy\nMeets 3.5/5 stated must-haves. Gaps: team management, Kubernetes (learning).\n\n### Summary\n<one line>\n\n### Triggered\n<red lines or failed gates with location, or \"none\">\n\n### Outcome\n<blank — the user fills this in later: applied / rejected / interviewing / offer / passed>\n```\n\n`minimal` — the heading, `Evaluated`, `Action`, `Summary`.\n\n`full` — adds a `### Raw JD` block. **Warn once before the first `full` write:**\n\"This stores the complete posting, which may include recruiter contact details or\ncomp not published elsewhere. Continue? (y/n)\". Do not re-ask on later writes.\n\n## OUT entries\n\nShorter body: no `Scores` or `Candidacy` sections — scoring stopped at the gate.\nKeep `Triggered` and `Summary`, and record the \"Matched anyway\" points under\n`Summary` so the signal is not lost.\n\n## The Outcome field\n\nLeft blank by the skill. If the user mentions an outcome in conversation\n(\"I applied to the Figma one\", \"they rejected me\"), offer to fill it in — never\nwrite it silently. Outcomes are what let `analyze` compare *predicted* fit with\n*actual* results; a file with none is still useful, just blind to that.\n\n## `/jd-triage history`\n\nLast 10 entries, one line each, newest last:\n\n```\nJD-20260712-001  Basecamp     Senior PM        ✅ Apply        Good/Plausible    applied\nJD-20260718-002  Northvolt    Product Lead     🗄️ Backup       Weak/Likely       —\nJD-20260725-001  Figma        PM, Dev Tools    🔥 Apply now    Strong/Plausible  —\n```\n\nSupport a filter argument: `/jd-triage history apply` shows only Apply-tier\nactions; `/jd-triage history out` only OUT.\n\n## `/jd-triage compare <id1> [<id2>]`\n\nTwo IDs, or one ID against the most recent, or \"the last two\".\n\n```\n                  JD-20260718-002        JD-20260725-001\n                  Northvolt              Figma\n                  Product Lead           PM, Dev Tools\n                  ──────────────         ──────────────\nAction            🗄️ Backup              🔥 Apply now\nDesirability      Weak (2.8)             Strong (4.2)\nCandidacy         Likely (85%)           Plausible (60%)\nCriteria version  4                      4\nRole fit          ★★★☆☆                  ★★★★★\nDomain            ★★☆☆☆                  ★★★★★\nOrg               ★★★★☆                  — (insufficient)\nVibe              ★★★☆☆                  ★★★★☆\nComp              ★★★★☆                  ★★★★☆\n\n<one line: which is stronger, and the trade the user is actually making>\n```\n\nThe closing line must name the trade-off rather than declare a winner — these two\ndiffer on *both* dimensions in opposite directions, which is the entire point of\nkeeping them apart.\n\n**Criteria drift warning.** If the two entries used different `Criteria version`\nvalues, prepend:\n\n```\n⚠️ Your criteria changed between these evaluations (v4 → v6).\n   Axes touched by the change are not directly comparable.\n```\n\nName which axes moved if the current file makes that determinable.\n\n## Growth\n\nThe file grows without bound by design — `analyze` gets better with more rows.\nIf it passes roughly 100 entries and the user asks, offer to archive entries\nolder than a year to `jd_history_<year>.md` rather than deleting them. Never\ndelete history unprompted.\n\nFile v1.1.1:references/intensity-signals.md\n\n# Intensity signals\n\nMaps job-posting language to `intensity_tier` for the hard gate. Load this when\nthe posting is not in English, or when its intensity is ambiguous.\n\nTiers, in order: `strict_hours` < `standard` < `high` < `always_on`.\nThe gate fails when the **JD's implied tier exceeds the user's**.\n\n## How to use it\n\n1. Scan the posting — including the benefits and culture sections, where the\n   strongest signals usually hide.\n2. Take the **highest** tier any matched phrase implies.\n3. No signal in either direction → assume the user's own tier, apply no penalty,\n   and say the posting was silent on it.\n4. A posting can carry signals from two tiers (\"flexible hours\" *and* \"on-call\n   rotation\"). Report both and take the higher; the contradiction itself is worth\n   an open question.\n\nPhrases below are indicative, not exhaustive — match meaning, not strings.\n\n## English\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"no overtime\", \"we don't work weekends\", \"core hours\", \"35-hour week\", \"strict work-life boundaries\", \"right to disconnect\" |\n| `standard` | \"occasional crunch around launches\", \"some evenings during release weeks\", \"fast-paced but sustainable\" |\n| `high` | \"fast-paced environment\", \"wear many hats\", \"hustle\", \"long hours\", \"whatever it takes\", \"we work hard and play hard\", \"comfortable with ambiguity and pace\", early-stage with no counterweight language |\n| `always_on` | \"on-call rotation\", \"24/7 coverage\", \"follow the sun\", \"global team across time zones\" with meetings outside local hours, \"always-on culture\" |\n\n## Chinese\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"不加班\", \"准时下班\", \"弹性工作\", \"双休\" with explicit no-overtime language |\n| `standard` | \"偶尔加班\", \"项目期加班\", \"节奏快但可持续\" |\n| `high` | \"高强度\", \"抗压能力强\", \"能接受加班\", \"创业心态\", \"狼性\", \"全力以赴\" |\n| `always_on` | \"996\", \"大小周\", \"单休\", \"7×12\", \"随时响应\", \"on-call 轮值\" |\n\n## Japanese\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"残業なし\", \"定時退社\", \"フレックス\", \"ワークライフバランス重視\" |\n| `standard` | \"繁忙期のみ残業あり\", \"月20時間程度の残業\" |\n| `high` | \"裁量労働制\" without stated caps, \"みなし残業\" with a high included-hours figure, \"ベンチャーマインド\", \"成長意欲の高い方\" |\n| `always_on` | \"オンコール\", \"24時間体制\", \"深夜対応あり\", \"サービス残業\" |\n\n## German\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"keine Überstunden\", \"Gleitzeit\", \"35-Stunden-Woche\", \"Vertrauensarbeitszeit\" with stated limits, \"Work-Life-Balance\" |\n| `standard` | \"gelegentliche Überstunden\", \"in Projektphasen\" |\n| `high` | \"hohe Belastbarkeit\", \"Hands-on-Mentalität\", \"dynamisches Umfeld\", \"Start-up-Mentalität\" |\n| `always_on` | \"Rufbereitschaft\", \"24/7-Support\", \"Schichtdienst\" |\n\n## French\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"35 heures\", \"droit à la déconnexion\", \"horaires fixes\", \"équilibre vie pro/vie perso\" |\n| `standard` | \"quelques pics d'activité\", \"heures supplémentaires occasionnelles\" |\n| `high` | \"forte capacité de travail\", \"environnement exigeant\", \"esprit start-up\", \"polyvalence\" |\n| `always_on` | \"astreinte\", \"support 24/7\", \"disponibilité permanente\" |\n\n## Spanish\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"jornada intensiva\", \"horario flexible\", \"sin horas extra\", \"conciliación\" |\n| `standard` | \"picos de trabajo puntuales\", \"horas extra ocasionales\" |\n| `high` | \"alta capacidad de trabajo\", \"ambiente exigente\", \"mentalidad startup\", \"resistencia a la presión\" |\n| `always_on` | \"guardias\", \"disponibilidad 24/7\", \"turnos rotativos\" |\n\n## Other languages\n\nReason from meaning using the tier definitions in\n`assets/criteria-template.yaml`, and state that you inferred rather than matched.\nIf the user confirms or corrects your reading, offer to append the phrase to this\nfile's table for their language so the next posting matches directly.\n\n## Watch for\n\n- **Benefits sections that contradict the duties.** \"Unlimited PTO\" next to\n  \"always available for our global customers\" is an `always_on` signal wearing a\n  `strict_hours` costume. Report the contradiction.\n- **Compensation structures implying hours** — a large \"included overtime\"\n  allowance, or a base that assumes on-call pay, implies `high` or above whatever\n  the culture section says.\n- **Silence in markets where hours are regulated.** In markets with statutory\n  limits, no mention of hours is weak evidence of `standard`, not of\n  `strict_hours`. Do not upgrade a posting on silence alone.\n\nFile v1.1.1:references/scoring.md\n\n# Scoring\n\nTwo dimensions, computed separately, never averaged together. Decision tiers and\nthe action matrix live in `SKILL.md § Decide` — this file defines how each number\nis produced.\n\n## Rules that apply to every axis\n\n- **1–5 only. No 3★ placeholders.** If the JD does not contain the information an\n  axis needs, output `(info insufficient)` and drop the axis from the average.\n- **Cite the JD.** Every score below 4★ or above 4★ names the phrase that drove\n  it. Quote the JD in its original language even when the surrounding output is\n  translated — a translated quote is no longer evidence.\n- **The criteria file is the only source of preference.** Never score against what\n  you happen to know about an industry, a city, or an employer's reputation.\n\n---\n\n## Desirability axes\n\n### Role fit — `target_title_keywords`, plus scope and seniority in the body\n\n| ★ | Meaning |\n|---|---|\n| 5 | Title matches a keyword, and the responsibilities match what the user means by that title |\n| 4 | Title clearly aligns, or matches with a different label but the same substance |\n| 3 | Adjacent — same family, different specialty, or a level off |\n| 2 | Related only through a shared word; the actual work is something else |\n| 1 | No match |\n\nRead the bullets, not just the header. The same title means different work at\ndifferent organizations — a title match with mismatched responsibilities is a\n3★, not a 5★, and the one-liner should say so.\n\n### Domain fit — `target_domains`\n\n| ★ | Meaning |\n|---|---|\n| 5 | The organization's main business is in the user's list |\n| 4 | In the list, but this role sits on an adjacent product or team |\n| 3 | One step removed — the domain is applied to a field the user did not ask for |\n| 2 | Tangential |\n| 1 | Not in the list |\n\n**Match by meaning, not by label.** The user wrote their domains in their own\nwords; a posting will use different ones. \"Forecasting and settlement software for\nregional grid operators\" *is* climate tech, and \"cohort-building tools for hospital\nresearch teams\" *is* health data, even though neither phrase appears in the list.\nName which listed domain you matched it to and why, so a wrong reading is visible\nand correctable. Reserve 1★ for a genuine miss, not a vocabulary mismatch.\n\n### Org fit — `org_traits`\n\nIdentify which of the user's traits this organization plausibly has, from the JD\nand its self-description only. Traits you cannot assess are simply not matched —\ndo not assume.\n\n| Situation | Score |\n|---|---|\n| One or more traits present | Weighted mean of the **present** traits' weights |\n| Traits were assessable, none of them present | **3★** — neutral |\n| Nothing about the organization can be assessed | `(info insufficient)` |\n\n**The absence of a preferred trait is not the presence of a rejected one.** An\nemployer that is merely *not* remote-first and *not* a research lab scores 3★, not\n1★. A low score requires a trait the user weighted 1–2 to actually be there — a\nposting that says \"a Thornbury Capital portfolio company\" against a stored\n`private-equity owned: 1` earns the 1★; a posting that simply never mentions\nownership does not.\n\nAn unknown employer with no self-description is the normal case, not a failure.\n\n### Vibe fit — `vibe_anchors_positive` / `vibe_anchors_negative`\n\nThe axis people rationalize away and then regret. Compare the JD's language,\nvalues statements, and product description against the anchors — **reasoning from\neach anchor's `why`, not from the anchor's reputation.**\n\n| ★ | Meaning |\n|---|---|\n| 5 | Multiple signals matching a positive anchor's `why`; nothing matching a negative one |\n| 4 | Clear positive-anchor alignment, no negative signals |\n| 3 | Genuinely neutral — the JD is written in standard corporate register and reveals little |\n| 2 | Some language matching a negative anchor's `why` |\n| 1 | Strong, repeated match to a negative anchor's `why` |\n\n**Mandatory citation format:**\n\n```\nVibe ★★☆☆☆  negative anchor \"<name>\" — its why: \"<the user's stated reason>\"\n            triggered by: \"<exact JD phrase>\", \"<exact JD phrase>\"\n```\n\nAn adjective without a quote is not a rating. \"Feels corporate\", \"seems\ngrowth-y\", \"no product taste\" are all invalid on their own.\n\n**Unknown organizations.** If you have no reliable knowledge of an anchor, that\nchanges nothing: the `why` is the comparison basis, and it always was. Never\nsubstitute a reputation for the user's stated reason — that is how the axis drifts\naway from the person it is supposed to represent. Equally, never refuse to score\nbecause an anchor is obscure.\n\n### Comp fit — `comp_floor`, `profile.current_comp`\n\nCompare **like for like** first. Normalize period (year / month / hour) and check\n`basis`:\n\n- JD quotes base, floor is `total` → not comparable. Mark `(info insufficient)`\n  and raise an open question asking for the full package.\n- Different currencies → convert only with a rate from `context.fx_rates`.\n  Without one, mark `(info insufficient)`. **Never invent an exchange rate.**\n- `context.comp_convention: n_month` → annualize using the stated multiplier\n  before comparing, and show the arithmetic.\n\n| ★ | Meaning |\n|---|---|\n| 5 | ≥ 130% of current comp |\n| 4 | 110–129% |\n| 3 | 100–109% — lateral |\n| 2 | Below current but at or above the floor |\n| 1 | Below the floor — the hard gate should already have caught this |\n\nNo comp stated in the JD → `(info insufficient)` plus an open question. This is\nthe most common case in many markets; it must not silently become a 3★.\n\n---\n\n## Combining the desirability axes\n\nWeighted mean using `axis_weights`. Axes marked `(info insufficient)` are removed\nand the remaining weights renormalized.\n\nWorked example — Org fit and Comp fit both unavailable:\n\n```\nRole fit  4  weight 25\nDomain    5  weight 20\nOrg       —  (info insufficient, dropped)\nVibe      2  weight 25\nComp      —  (info insufficient, dropped)\n\nRemaining weight = 25 + 20 + 25 = 70\nWeighted = (4×25 + 5×20 + 2×25) / 70 = (100 + 100 + 50) / 70 = 3.57\nDesirability tier: Good  →  capped at Weak by the vibe ≤ 2★ rule\n```\n\nShow the renormalized denominator whenever an axis was dropped, so the user can\nsee the verdict rests on three axes rather than five.\n\nIf **three or more** axes are insufficient, do not report a tier. Say the posting\nis too thin to score and list what to ask for.\n\n---\n\n## Candidacy\n\n### Extract the requirements\n\nSplit the JD's requirements into **must-have** and **preferred**. Markers vary by\nlanguage and market; treat anything hedged — preferred, nice to have, a plus,\nbonus, ideally, 优先, wünschenswert, 尚可 — as preferred.\n\nAmbiguous section with no split marker → treat everything as must-have and note\nthe assumption.\n\n### Score\n\n| Requirement matches | Credit |\n|---|---|\n| an item in `skills.mastered` | 1.0 |\n| an item in `skills.learning` | 0.5 |\n| nothing | 0 |\n\nYears of experience is one requirement, met if `profile.years_of_experience` is\nwithin one year of the stated minimum. A stated maximum is not a requirement.\n\n`hit_rate = credit_earned / count(must_have)`\n\n| Tier | Hit rate |\n|---|---|\n| **Likely** | ≥ 75% |\n| **Plausible** | 40–74% |\n| **Stretch** | < 40% |\n| **Unknown** | fewer than 3 stated must-haves |\n\nWorked example:\n\n```\nMust-haves (5):\n  5+ years in the field          → profile says 6         1.0\n  SQL                            → mastered               1.0\n  Experiment design              → mastered               1.0\n  Kubernetes                     → learning               0.5\n  Managed a team of 3+           → no match               0\n\ncredit 3.5 / 5 = 70%  →  Plausible\nPreferred (not counted): German at C1, healthcare experience\n```\n\n### Reporting rules\n\n- **Count only what the JD states.** Never add a requirement the posting does not\n  contain, however standard it seems for the role.\n- **Never map seniority across markets.** L5, P7, Senior II, 主管, and Grade 6 are\n  not comparable. Count stated requirements; ignore the level label.\n- **Report gaps as facts plus context**, e.g. *\"No team-management evidence — this\n  is usually probed with 'tell me about a time you gave difficult feedback', so\n  it is answerable from mentoring experience if you have any.\"* Not a verdict on\n  the person.\n- **No inflation.** Do not round `learning` up to `mastered` because the user\n  seems close. The half-credit exists so the honest answer is the useful one.\n- **No catastrophizing.** A Stretch is a real option with a named gap, not a\n  rejection. Say which one or two items would move it to Plausible.\n- Preferred requirements the user *does* meet are worth mentioning — they are\n  interview material even though they do not affect the tier.\n\nFile v1.1.1:skill-card.md\n\n## Description:\n\nScores a job posting on separate desirability and candidacy dimensions, then returns a concrete action for the job seeker.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[bwancoding](https://clawhub.ai/user/bwancoding)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nJob seekers use this skill to evaluate pasted job postings or recruiter messages against their own criteria and skills. It can also maintain criteria, log evaluations, compare prior roles, analyze accumulated history, and suggest what to learn next for a target role.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill stores a local career profile and appends a record for every evaluated role, which may expose sensitive career preferences, compensation details, recruiter contacts, or posting text in shared or synced workspaces.\n\nMitigation: Use it in a private workspace, keep full history disabled unless needed, and review history files before syncing, sharing, or committing them.\n\nRisk: The skill can add learned language phrases to its reference material, which could preserve unreviewed prompt content as reusable data.\n\nMitigation: Review any proposed reference-file additions and store only plain data that has been checked for privacy, accuracy, and prompt-injection content.\n\nRisk: The security verdict is suspicious because the skill persists sensitive career data and can modify its own reference material.\n\nMitigation: Review the skill and its generated workspace files before deployment, and limit use to agents and workspaces where local file writes are expected.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/bwancoding/skills/jd-triage)\n- [OpenClaw](https://github.com/openclaw)\n- [README](artifact/README.md)\n- [Scoring](artifact/references/scoring.md)\n- [Bootstrap](artifact/references/bootstrap.md)\n- [History](artifact/references/history.md)\n- [Analyze & Plan](artifact/references/analysis-commands.md)\n- [Intensity Signals](artifact/references/intensity-signals.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Configuration, Guidance]\n\n**Output Format:** [Markdown responses and markdown workspace files]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces a verdict, scoring rationale, open questions, criteria updates, and append-only evaluation history.]\n\n## Skill Version(s):\n\n1.1.1 (source: server release metadata and artifact _meta.json)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.1.1:assets/criteria-template.yaml\n\n# jd_criteria.md — schema v3\n#\n# Written to ~/.openclaw/workspace/jd_criteria.md by the jd-triage skill.\n# Field keys are English and machine-readable. Values are in whatever language\n# you wrote them in, and are never auto-translated.\n#\n# Hand-editing is expected and supported. The skill parses what it finds and\n# asks about anything malformed rather than overwriting it.\n\nschema_version: 3\ncriteria_version: 1\nlast_updated:                 # ISO-8601, e.g. 2026-07-25\n\nhistory_detail: standard      # minimal | standard | full\n                              #   minimal  — org, title, action, date\n                              #   standard — + both dimensions, scores, one-liner (default)\n                              #   full     — + raw JD text (may contain recruiter contact\n                              #              details or unposted comp; you are warned once)\n\n# ─────────────────────────────────────────────────────────────\n# Context — establishes the vocabulary for everything below.\n# Fill this first: it tells the skill which market conventions,\n# comp structures, and intensity signals apply to you.\n# ─────────────────────────────────────────────────────────────\ncontext:\n  role_family:                # free text, e.g. \"product management\",\n                              # \"backend engineering\", \"brand design\",\n                              # \"clinical research\", \"policy\"\n  market:                     # where you are looking, e.g. \"Germany\",\n                              # \"US remote\", \"mainland China tech\", \"Japan\"\n  languages: []               # languages you can work in, e.g. [\"English\", \"German\"]\n  comp_convention:            # how comp is normally quoted where you are looking:\n                              #   total          — one all-in number\n                              #   base_plus_var  — base + bonus and/or equity, quoted separately\n                              #   n_month        — annual = monthly × N (e.g. 13th/14th month)\n                              #   hourly | daily — contract / freelance\n  fx_rates: {}                # optional, only if you compare across currencies,\n                              # e.g. {USD_per_EUR: 1.08}. The skill will not\n                              # invent a rate; without one it flags the mismatch.\n\n# ─────────────────────────────────────────────────────────────\n# Profile — you, right now\n# ─────────────────────────────────────────────────────────────\nprofile:\n  years_of_experience:        # integer\n  current_title_org:          # free text, e.g. \"PM @ Acme\"\n  current_comp:\n    amount:                   # number\n    currency:                 # ISO code, e.g. USD, EUR, CNY, JPY\n    period:                   # year | month | hour\n    basis:                    # total | base\n    notes:                    # anything the numbers do not capture,\n                              # e.g. \"14 months\", \"+ RSU ~15%\", \"pre-tax\"\n\n# ─────────────────────────────────────────────────────────────\n# Skills — the input to the Candidacy dimension.\n# Be honest about the split: `learning` items score half credit,\n# so inflating `mastered` only produces worse advice.\n# ─────────────────────────────────────────────────────────────\nskills:\n  mastered: []                # you could be interviewed on this today\n  learning: []                # actively building; half credit toward requirements\n  want_to_learn: []           # not started; used by `plan`, not by scoring\n\n# ─────────────────────────────────────────────────────────────\n# Target roles — archetypes you are aiming at. Drives `plan`.\n# ─────────────────────────────────────────────────────────────\ntarget_roles: []\n  # - id: short_slug\n  #   name: \"Human-readable role name\"\n  #   description: \"What this role actually does, in your words\"\n\n# ─────────────────────────────────────────────────────────────\n# Hard gates — a failure ends the evaluation (red lines are weighted)\n# ─────────────────────────────────────────────────────────────\nhard_gates:\n  comp_floor:\n    amount:\n    currency:\n    period:                   # year | month | hour\n    basis:                    # total | base — compared like-for-like against the JD\n  locations: []               # e.g. [\"Berlin\", \"Amsterdam\"]\n  remote_ok:                  # yes | no | hybrid_only\n  intensity_tier:             # strict_hours | standard | high | always_on\n                              #   strict_hours — fixed hours, evenings and weekends off\n                              #   standard     — occasional crunch around releases\n                              #   high         — long hours normal, some weekends expected\n                              #   always_on    — on-call, cross-timezone, no clear boundary\n  red_lines: []               # matched semantically, then weighted by where it sits\n                              # in the JD. The `why` is what makes cross-language and\n                              # reworded matches work — do not omit it.\n  # - pattern: \"revenue ownership\"\n  #   why: \"I do not want a quota; it changes what the job optimizes for\"\n  # - pattern: \"on-call rotation\"\n  #   why: \"health reasons, non-negotiable\"\n\n# ─────────────────────────────────────────────────────────────\n# Soft axes — scored 1-5 per JD, combined using axis_weights\n# ─────────────────────────────────────────────────────────────\nsoft_axes:\n  target_title_keywords: []   # titles you want to see in the header\n  target_domains: []          # what the org does, e.g. [\"developer tools\",\n                              # \"public health\", \"climate hardware\"]\n\n  org_traits: []              # replaces fixed company-type/size enums: describe\n                              # traits in your own words and weight them 1-5\n                              # (1 = actively avoid, 5 = strongly prefer)\n  # - trait: \"research lab with a shipping product\"\n  #   weight: 5\n  # - trait: \"private-equity owned\"\n  #   weight: 1\n  # - trait: \"under 50 people\"\n  #   weight: 2\n\n  vibe_anchors_positive: []   # organizations, teams, or products you admire.\n                              # `why` is mandatory and load-bearing: it is what\n                              # lets the skill reason about an org it has never\n                              # heard of, and what keeps it from inventing a\n                              # reputation for one it has.\n  # - name: \"Linear\"\n  #   why: \"restraint — a clear product opinion, no feature-count race\"\n\n  vibe_anchors_negative: []   # same shape; energy you actively avoid\n  # - name: \"<a place you left>\"\n  #   why: \"manufactured urgency, metrics used as a loyalty test\"\n\n# ─────────────────────────────────────────────────────────────\n# Axis weights — must sum to 100. Axes with insufficient\n# information drop out and the rest are renormalized.\n# ─────────────────────────────────────────────────────────────\naxis_weights:\n  role_fit: 25\n  domain_fit: 20\n  org_fit: 15\n  vibe_fit: 25\n  comp_fit: 15\n\nFile v1.1.1:assets/presets/knowledge-work.yaml\n\n# Preset: profession-neutral knowledge work\n# (consulting, research, policy, marketing, operations, finance, legal, education)\n#\n# Use this when no other preset fits, or when the user's field is outside tech.\n# A preset is a MENU, not a default. Offer these lines, let the user pick and\n# reword, and write only what they chose.\n\npreset_id: knowledge-work\nlabel: \"Knowledge work — general\"\n\nsuggested_org_traits:\n  - \"mission-driven or nonprofit\"\n  - \"public sector or government\"\n  - \"academic or research institution\"\n  - \"professional services firm\"\n  - \"family-owned or founder-controlled\"\n  - \"publicly traded\"\n  - \"heavily regulated industry\"\n  - \"under 50 people\"\n  - \"international, English-speaking office\"\n\nsuggested_red_line_starters:\n  - \"billable-hours target\"\n  - \"significant travel required\"\n  - \"fixed on-site five days a week\"\n  - \"individual sales or fundraising quota\"\n  - \"rotating shifts\"\n\nvibe_prompt: >\n  Name 1-3 organizations or teams you would be glad to work in — any sector, any\n  size, including ones only people in your field would recognize. One line each\n  on WHY. The reason is what the skill actually reasons from.\n\naxis_weights:\n  role_fit: 25\n  domain_fit: 20\n  org_fit: 15\n  vibe_fit: 25\n  comp_fit: 15\n\nFile v1.1.1:assets/presets/people-lead.yaml\n\n# Preset: manager / lead track (any function)\n#\n# A preset is a MENU, not a default. Offer these lines to the user during Quick\n# Start, let them pick and reword, and write only what they chose. Never write a\n# preset value into jd_criteria.md without the user selecting it.\n\npreset_id: people-lead\nlabel: \"Manager / lead track\"\n\nsuggested_org_traits:\n  - \"flat org, few management layers\"\n  - \"team already exists (not a hire-from-zero mandate)\"\n  - \"budget authority for the team\"\n  - \"reports directly to a founder or executive\"\n  - \"matrixed reporting\"\n  - \"recently through layoffs or restructuring\"\n  - \"distributed team across timezones\"\n\nsuggested_red_line_starters:\n  - \"player-coach with a full IC workload\"\n  - \"no hiring authority for my own team\"\n  - \"team inherited mid-performance-plan\"\n  - \"reorg announced but not completed\"\n\nvibe_prompt: >\n  Name 1-3 teams or organizations whose *way of working* you admire — how they\n  make decisions, handle disagreement, treat people leaving. One line each on\n  WHY. For a leadership role the culture reason is the signal, not the logo.\n\n# Leadership roles are judged more on the org than on the title,\n# and comp bands are wider — weights shift accordingly.\naxis_weights:\n  role_fit: 20\n  domain_fit: 15\n  org_fit: 25\n  vibe_fit: 25\n  comp_fit: 15\n\nArchive v1.1.0: 13 files, 32605 bytes\n\nFiles: _meta.json (128b), assets/criteria-template.yaml (8678b), assets/presets/knowledge-work.yaml (1245b), assets/presets/people-lead.yaml (1308b), assets/presets/tech-ic.yaml (1245b), README.md (5369b), references/analysis-commands.md (4902b), references/bootstrap.md (8282b), references/history.md (4812b), references/intensity-signals.md (4632b), references/scoring.md (8786b), skill-card.md (2693b), SKILL.md (15963b)\n\nFile v1.1.0:SKILL.md\n\n---\nname: jd-triage\ndescription: \"Career decision system for job seekers. Scores a job description on two independent dimensions — how much you want it (5 weighted axes against your stored criteria) and how likely you are to get it (your skills vs the JD's stated requirements) — then returns one concrete action. Use when (1) the user pastes a job description or recruiter message, (2) the user invokes /jd-triage or asks 'should I apply for this role', (3) the user asks to list, compare, or analyze previously evaluated roles, (4) the user asks what to learn next for a target role, (5) the user asks to set up, update, or reset their career criteria. Market-, language-, and profession-neutral; bootstraps a criteria profile on first run.\"\n---\n\n# jd-triage · v1.1.0\n\nA JD is evaluated on **two independent dimensions**, never collapsed into one number:\n\n- **Desirability** — do you want this? Five weighted axes scored against the user's stored criteria.\n- **Candidacy** — can you get this? The JD's stated must-have requirements vs the user's skills inventory.\n\nA role you want but can't get is a *stretch*, not a *skip*. A role you can get but don't want is a *backup*, not an *apply*. Collapsing both into one star rating destroys that distinction — which is the whole decision.\n\nResponsibilities:\n\n1. **Bootstrap & maintain** a criteria profile at `~/.openclaw/workspace/jd_criteria.md`.\n2. **Evaluate** a JD → two-dimension verdict + one action.\n3. **Log** every evaluation to `~/.openclaw/workspace/jd_history.md`.\n4. **Analyze / Plan** over accumulated history (see `references/analysis-commands.md`).\n\n## Language\n\n**Default to English.** If the user writes in another language, respond entirely in that language for the rest of the session.\n\n| Surface | Language |\n|---|---|\n| All conversational output — bootstrap Q&A, verdicts, tables | User's language (English by default) |\n| `jd_criteria.md` field keys, `jd_history.md` structural labels, verdict tier names **in storage** | **Always English** — grep-friendly, stable across language switches |\n| Stored free-text values (org names, summaries, red-line rationales, JD quotes) | The language the user wrote them in, at write time |\n\n**Never auto-translate stored content.** When listing or comparing entries written in different languages, render structural labels in the current language and show stored free text verbatim. Quotes pulled from a JD keep the JD's original language even when the surrounding output is translated — a translated quote is no longer evidence.\n\n## State machine\n\nOn every invocation, read `~/.openclaw/workspace/jd_criteria.md` and branch:\n\n| State | Condition | Action |\n|---|---|---|\n| **S1: Missing** | File does not exist | **Quick Start** (5 questions) → proceed to the requested command |\n| **S2: Schema gap** | File exists, `schema_version` < 3 | Migrate silently where possible, ask only for fields that cannot be inferred (see `references/bootstrap.md § Migration`) |\n| **S3: Fresh** | Complete, `last_updated` ≤ 30 days ago | Proceed directly. Note \"Using criteria from `<date>`\" in one line |\n| **S4: Stale** | Complete, `last_updated` > 30 days ago | Ask once: \"Anything changed — comp, location, red lines, what you're learning? (y/n)\". `n` → refresh timestamp only. `y` → user names the fields, patch those |\n| **S5: Explicit update** | \"update criteria\" / `/jd-triage update` / `/jd-triage reset` | Full bootstrap, current values pre-filled |\n\n`criteria_version` increments on every S1 / S2 / S5 write. S4 \"nothing changed\" bumps `last_updated` only.\n\nIf the invocation included a JD, continue to Evaluation after the criteria are settled. Otherwise execute the requested command and stop.\n\n## Commands\n\n| Input | Action |\n|---|---|\n| A pasted JD, or `/jd-triage` | Evaluate |\n| `/jd-triage update` \\| `reset` | S5 bootstrap |\n| `/jd-triage quickstart` | Force the 5-question Quick Start |\n| `/jd-triage learn` | Derive criteria from example JDs (`references/bootstrap.md § Derive from examples`) |\n| `/jd-triage history` | Last 10 entries, one line each |\n| `/jd-triage compare <id1> [<id2>]` | Side-by-side table |\n| `/jd-triage analyze` | Market signals across history → `references/analysis-commands.md` |\n| `/jd-triage plan` | Skill-gap plan per target role → `references/analysis-commands.md` |\n\nA past role referred to by org name resolves to an ID by grepping `jd_history.md`.\n\n## Evaluation\n\n### 1. Parse\n\nExtract: title, org name, responsibilities, **must-have requirements**, **preferred requirements** (keep these separate — the split drives Candidacy), comp, location and remote policy, intensity signals, reporting line, team size.\n\nIf the input has a title but no responsibilities or requirements, **stop and ask for the full posting.** Do not evaluate a title.\n\n### 2. Hard gates\n\nFailures produce **❌ OUT** and stop — except red lines, which are weighted (below).\n\n- `comp_floor` — compare like for like: the JD's basis (base / total / hourly) against the floor's basis, in the same currency and period. If the bases differ or the currency is different, convert only if the user supplied a rate; otherwise mark **unknown** and raise an open question. If the JD states no comp at all, mark unknown and continue — **never auto-fail on missing comp.**\n- `locations` / `remote_ok` — JD location must be in the list, or the JD must be remote-eligible under the user's `remote_ok` setting.\n- `intensity_tier` — the JD's implied tier must not exceed the user's. Signal patterns are per-language in `references/intensity-signals.md`. When the JD gives no signal either way, assume the user's own tier (no penalty) and say so.\n- `red_lines` — match **semantically**, not by substring. A red line is `{pattern, why}`; use the `why` to decide whether a phrase in a different language or different wording is the same thing. Then weight by position:\n\n  | Where the matched responsibility sits | Verdict |\n  |---|---|\n  | In the title, in the first 1–2 responsibility bullets, or plausibly >30% of the role | **❌ OUT** — core |\n  | Only in tail bullets, framed as support/assist/partner-with | **⚠️ CONDITIONAL** — score normally, flag it, raise an open question |\n  | Only in the requirements/preferred section, not in the duties | Note as an open question, do not gate |\n\n  Always cite the matched phrase **and its location** (\"bullet 6 of 7, framed as 'support'\"). A bare keyword is not a citation — the user needs the framing to judge.\n\n  Semantic matching cuts both ways: it must not fire on incidental use. A red line of \"growth\" does not match \"growth mindset\" in a values paragraph. State what you matched and let the user correct you.\n\n### 3. Desirability — 5 weighted axes\n\nScore each 1–5 per `references/scoring.md`. Weights come from `axis_weights` in the criteria file (defaults there too).\n\n| Axis | Scored against | Default weight |\n|---|---|---|\n| **Role fit** | `target_title_keywords`, seniority and scope of the role | 25% |\n| **Domain fit** | `target_domains` — what the org actually does | 20% |\n| **Org fit** | `org_traits` — user-described traits with their own weights | 15% |\n| **Vibe fit** | `vibe_anchors_positive` / `_negative`, each carrying a `why` | 25% |\n| **Comp fit** | `comp_floor` and `profile.current_comp` | 15% |\n\n**Never pad.** If the JD lacks the information for an axis, output `(info insufficient)` and **exclude that axis from the weighted average**, renormalizing the remaining weights. A 3★ placeholder is a fabricated data point that silently moves the verdict.\n\n**Vibe must cite.** Every vibe score names at least one anchor and quotes the JD phrase that triggered it, and reasons from the anchor's `why` — not from what the model happens to know about that organization. Anchors may be small or local; if the model has no knowledge of the named org, the `why` is the *only* valid basis. Adjective-only judgments (\"feels corporate\") are forbidden.\n\n### 4. Candidacy — can you get it?\n\nIf `skills` is empty — the normal state after Quick Start — ask for it once,\ninline, before scoring: *\"To score whether you can get this, I need your skills:\nwhat could you be interviewed on today, and what are you actively learning?\"*\nSave the answer so this is never asked twice.\n\nCompare the JD's **must-have** requirements against `skills` and `profile`:\n\n- Each requirement scores `1.0` if it matches `skills.mastered`, `0.5` if it matches `skills.learning`, `0` otherwise.\n- Years-of-experience counts as one requirement; met if `profile.years_of_experience` is within one year of the stated minimum.\n- **Preferred / nice-to-have requirements are excluded from the denominator** and reported separately.\n- Hit rate → tier: **Likely** ≥75%, **Plausible** 40–74%, **Stretch** <40%.\n- Fewer than 3 stated must-haves → **Unknown**; do not guess, raise an open question instead.\n\nDo not invent requirements the JD does not state. Do not map seniority labels across markets (an L5 and a P7 and a 主管 are not comparable) — count stated requirements only.\n\nReport gaps honestly in both directions: no inflation (\"you basically have this\"), no catastrophizing. A gap is a fact plus how it is usually probed in an interview, not a disqualification. Items in `skills.learning` are real partial credit — say so.\n\n### 5. Decide\n\nApply in this order. **The first rule that fires wins; stop there.**\n\n1. Hard gate failed → **❌ OUT**\n2. Red line in a non-core responsibility, **or** an unknown that could flip the verdict (comp, location, or scope) → **⚠️ CONDITIONAL**\n\n   Test whether the unknown can actually flip anything before invoking this. An\n   unknown that is already bounded on the deciding side is an **open question, not\n   a conditional**: a posting quoting €95,000 base against a €90,000 *total* floor\n   leaves comp unscoreable, but the gate is settled — base alone cannot make the\n   total fall below the floor. Say so and carry on to the matrix. Reserve\n   CONDITIONAL for unknowns whose resolution genuinely changes the answer.\n3. Otherwise → look up the matrix\n\nDesirability tier from the weighted average — checked top to bottom, **first\nmatch wins**, so a high average with one collapsed axis falls through rather than\nqualifying:\n\n- **Strong** — ≥ 4.0 and no axis ≤ 2\n- **Good** — ≥ 3.2 and no axis = 1\n- **Weak** — ≥ 2.4\n- **Poor** — < 2.4\n\nOne override: **vibe ≤ 2★ caps desirability at Weak**, whatever the average says. Vibe is the axis people rationalize away and regret.\n\n| | Likely | Plausible | Stretch |\n|---|---|---|---|\n| **Strong** | 🔥 Apply now | 🔥 Apply now | 🎯 Stretch apply |\n| **Good** | ✅ Apply | ✅ Apply | 🎯 Stretch apply |\n| **Weak** | 🗄️ Backup | 🗄️ Backup | ❌ Skip |\n| **Poor** | ❌ Skip | ❌ Skip | ❌ Skip |\n\nCandidacy **Unknown** → read the **Plausible** column, mark the result provisional\n(`✅ Apply (provisional)`), and put a question about the actual requirements first\nunder Open questions. Never silently drop to a one-dimensional verdict.\n\nDesirability **too thin to score** (three or more axes insufficient, per\n`references/scoring.md`) → the verdict is **⚠️ CONDITIONAL**, written as\n`Desirability: (too thin to score)`. There is no tier to report and no matrix to\nread; what the posting is missing goes under Open questions.\n\n### 6. Log\n\nAppend to `~/.openclaw/workspace/jd_history.md` — format and ID scheme in `references/history.md`. Create the file if missing.\n\n**The evaluation is not complete until this write succeeds.** Confirm it on the last line of the output (`Logged: JD-…`). If the write fails, say so explicitly — never let it fail silently.\n\n### 7. Output\n\nThe first line is the verdict line, and it is **parsed** — by `history`, by\n`compare`, by anything reading the log later. Write the tier token exactly as\nspelled below, in that casing, and never substitute the action wording for it:\n\n`Apply now` · `Apply` · `Stretch apply` · `Backup` · `Skip` · `OUT` · `CONDITIONAL`\n\nSo a conditional verdict opens `⚠️ CONDITIONAL`, never `⚠️ Confirm before applying`\n— the latter belongs on the Action line inside the body. Do not uppercase, retitle,\nor decorate the token.\n\nIf the criteria were reused rather than collected, put `Using criteria from <date>`\non its own line **above** the verdict line, never below or inside it.\n\n```\n<emoji> <TIER>          Desirability: <tier>   Candidacy: <tier>\n\nWant it\n  Role fit     ★★★★☆\n  Domain       ★★★★★\n  Org          ★★★☆☆\n  Vibe         ★★☆☆☆   anchor \"<name>\" — \"<JD phrase>\"\n  Comp         ★★★★☆\n  → weighted <n.n>/5\n\nCan get it\n  Meets <k>/<n> stated must-haves\n  ✅ <met>            ⚠️ <partial — in progress>            ❌ <gap>\n\n<one sentence: the actual judgment>\n\nOpen questions\n- <only real unknowns; omit the section entirely if none>\n\nLogged: JD-YYYYMMDD-NNN\n```\n\n**CONDITIONAL** — same shape, but the one-liner must carry the conditional explicitly: *\"Fits if `<X>` is confirmed; OUT if `<X>` turns out to be core.\"* Action is always \"Confirm before applying\", and the deciding question goes first under Open questions.\n\n**OUT** — short form, but never empty-handed:\n\n```\n❌ OUT\nTriggered: <gate or red line, with location and exact phrase>\n<one sentence: why>\n\nMatched anyway\n- <aligned dimensions worth remembering — omit if genuinely none>\n\nLogged: JD-YYYYMMDD-NNN\n```\n\nThe \"Matched anyway\" block exists so that rejections still accumulate signal about what to look for.\n\n## Behavioral constraints\n\n- **OUT means OUT.** Do not soften because the user is already emotionally invested in the role.\n- **Never pad a score.** Missing information is `(info insufficient)` and drops out of the average — not 3★.\n- **Never pre-fill from training data.** Criteria values come only from the user. Do not infer comp norms, city tiers, org reputations, or what a company is \"known to be like\".\n- **Reason from the user's `why`, not from fame.** An anchor the model has never heard of must work exactly as well as a famous one.\n- **Red lines are weighted, not literal**, and semantic, not substring.\n- **Keep the two dimensions apart.** Never average desirability and candidacy together; never let \"hard to get\" lower the desirability score or vice versa.\n- **Open questions are output, not internal state.** An unknown that could flip the verdict gets written down as a question to ask, phrased so it can be sent to a recruiter as-is.\n- **One JD at a time.** Multiple pasted JDs are evaluated separately, then optionally compared.\n- **No hollow encouragement.** No \"good luck\", no \"hope this helps\".\n- **Trust hand edits.** If the user edited `jd_criteria.md`, parse what is there. If a field is malformed, quote the line and ask — never silently overwrite.\n- **Analyze and plan need real data.** Below the thresholds in `references/analysis-commands.md`, say so and stop.\n\n## Detection triggers\n\n- A pasted block that reads like a job posting: a title-like line plus responsibilities or requirements. Length alone is not a trigger — do not claim any long paste.\n- `/jd-triage` and its subcommands.\n- \"should I apply\", \"is this role worth it\", \"evaluate this JD\", \"what should I learn next\", \"what patterns do you see in the roles I've looked at\", and their equivalents in the user's language.\n\n## Files\n\n| File | Loaded when |\n|---|---|\n| `assets/criteria-template.yaml` | Writing the criteria file |\n| `assets/presets/*.yaml` | Quick Start, to pre-fill structure |\n| `references/bootstrap.md` | S1 / S2 / S5, or `/jd-triage learn` |\n| `references/scoring.md` | Every evaluation |\n| `references/intensity-signals.md` | Intensity gate, when the JD is not in English |\n| `references/history.md` | Logging, `history`, `compare` |\n| `references/analysis-commands.md` | `analyze`, `plan` |\n\nLoad a reference only when its flow runs.\n\nFile v1.1.0:README.md\n\n# jd-triage\n\n**Two questions, kept apart: do you want it, and can you get it?**\n\nPaste a job posting. Get a verdict against the criteria *you* defined — plus an\nhonest read on whether you'd clear the bar. Most JD filters collapse both into\none score, which is exactly the information you needed.\n\nA skill for [OpenClaw](https://github.com/openclaw). Works in any market, any\nlanguage, any profession.\n\n---\n\n## What it does\n\n- **Scores two independent dimensions.** Desirability from five weighted axes\n  against your stored criteria; Candidacy from the posting's stated must-haves\n  against your skills. A role you want but can't get is a **stretch**, not a\n  skip. A role you can get but don't want is a **backup**, not an apply.\n- **Weights red lines by where they appear.** \"Owns revenue targets\" in the title\n  is an instant no. The same phrase in the last bullet, framed as *support*, is a\n  question to ask the recruiter — not a rejection.\n- **Makes vibe judgments inspectable.** Every vibe rating quotes the posting and\n  names the anchor it reasoned from. Anchors carry your *reason*, so the skill\n  works on a 12-person studio nobody has heard of, not just famous logos.\n- **Turns unknowns into questions.** Missing comp, ambiguous scope, unclear\n  remote policy — each becomes a line you can paste into a reply to the recruiter.\n- **Logs everything, including rejections.** Over time, `analyze` shows which\n  patterns keep reaching you and which requirement you keep almost meeting.\n\n## Starting up\n\nFive questions. Not thirteen.\n\nQuick Start asks for your role family and market, what titles you want, your\nfloors (comp with basis, locations, remote), your automatic no's, and one to\nthree organizations you admire *with a line on why each*. That is enough to\nevaluate. Everything else is asked once, at the moment it first matters.\n\nPrefer showing over telling? `/jd-triage learn` reads a handful of postings you\nliked and a handful you passed on, then proposes your red lines and anchors for\nyou to accept or edit.\n\n## Commands\n\n| Command | What it does |\n|---|---|\n| Paste a posting, or `/jd-triage` | Evaluate |\n| `/jd-triage quickstart` | The 5-question setup |\n| `/jd-triage learn` | Derive criteria from example postings |\n| `/jd-triage update` \\| `reset` | Edit criteria, current values pre-filled |\n| `/jd-triage history [apply\\|out]` | Last 10 evaluations |\n| `/jd-triage compare <id1> [<id2>]` | Side by side |\n| `/jd-triage analyze` | Patterns across everything you've evaluated (needs 8+) |\n| `/jd-triage plan` | Which gap to close next, ranked by what postings actually ask for |\n\nNatural language works too, in your language: \"should I apply to this\",\n\"和上次对比\", \"what should I learn next\".\n\n## Sample output\n\n```\n🎯 STRETCH APPLY        Desirability: Strong   Candidacy: Stretch\n\nWant it\n  Role fit     ★★★★★\n  Domain       ★★★★★\n  Org          ★★★★☆\n  Vibe         ★★★★☆   anchor \"Basecamp\" — why: \"small team, no growth theater\"\n                       triggered by: \"we ship deliberately\", \"no on-call\"\n  Comp         — (info insufficient)\n  → weighted 4.6/5 across 4 axes\n\nCan get it\n  Meets 2/5 stated must-haves\n  ✅ SQL   ✅ experiment design\n  ⚠️ Kubernetes (learning — half credit)\n  ❌ 5 years managing a team   ❌ regulated-industry experience\n\nStrong on everything you control; the management requirement is the one real\nblocker, and it's the kind they usually probe rather than verify.\n\nOpen questions\n- Is the team-management requirement firm, or would mentoring experience clear it?\n- What's the full package, and is the posted number base or all-in?\n\nLogged: JD-20260725-001\n```\n\n## Files it writes\n\n- `~/.openclaw/workspace/jd_criteria.md` — your criteria\n- `~/.openclaw/workspace/jd_history.md` — append-only evaluation log\n\nPlain markdown, hand-editable. The skill parses your edits and asks about\nanything malformed instead of overwriting it.\n\n## Privacy\n\nHistory stores verdicts, scores, and a one-line summary — **not the raw posting**.\nSet `history_detail: full` to keep raw text; you'll be warned once. Recruiter\ncontact details and unposted comp live in those postings, so don't turn it on for\na workspace you sync publicly.\n\n## Limitations\n\n- **It does not read your resume.** Candidacy is scored from the skills inventory\n  you provide, against what the posting actually states. It will not tell you how\n  you compare to other applicants.\n- **It does not map seniority across markets.** L5, P7, and Grade 6 are not\n  comparable, so it counts stated requirements and ignores the level label.\n- **Vibe is only as good as your anchors' reasons.** The `why` is what it reasons\n  from. One-word anchors produce weak ratings — that is the design working, not\n  failing.\n- **The sample is your inbox.** `analyze` describes the roles reaching you, never\n  \"the market\".\n- **No comp negotiation advice.** Out of scope.\n- **Model support is measured, not assumed.** Verified on GLM-5.2 and Claude\n  Sonnet 4.6 — 18 test cases, 100% verdict stability across repeated runs and\n  100% compliance with the skill's own rules. Smaller models are simply untested;\n  no claim either way.\n\n## Author\n\nBarry Wang ([@bwancoding](https://github.com/bwancoding)) —\n[github.com/bwancoding/jd-triage](https://github.com/bwancoding/jd-triage)\n\nMIT licensed.\n\nFile v1.1.0:_meta.json\n\n{\n  \"ownerId\": \"kn7fsvwdsd1ktv3vdfztehe7mx821jdh\",\n  \"slug\": \"jd-triage\",\n  \"version\": \"1.1.0\",\n  \"publishedAt\": 1785003585334\n}\n\nFile v1.1.0:references/analysis-commands.md\n\n# Analyze & Plan\n\nBoth commands read accumulated history. Both refuse to run on too little data —\na trend drawn from four postings is a horoscope.\n\n| Command | Needs | Below that |\n|---|---|---|\n| `/jd-triage analyze` | ≥ 8 entries in `jd_history.md` | Say how many exist and how many more are needed. Do not produce a partial report |\n| `/jd-triage plan` | `skills` and at least one `target_roles` entry | Point at `/jd-triage update`. If history has ≥ 8 entries, use it to rank gaps; otherwise say the ranking is based on the role description alone |\n\n**Report only what is in the data.** Empty category → \"none yet\". Never fill a\nsection by inference.\n\n---\n\n## `/jd-triage analyze`\n\nRead every entry plus the criteria file.\n\n```\n📊 <N> roles evaluated, <first date> → <last date>\n\nWhere they came from\n  <org trait>: <n>          ← grouped by the user's own org_traits vocabulary\n  <org trait>: <n>\n  unclassified: <n>\n\nTitles that keep appearing\n  <title pattern>: <n>\n\nWhat they ask for\n  <requirement>: <n>/<N> postings — you have it (mastered)\n  <requirement>: <n>/<N> postings — you're learning it       ← highest ROI\n  <requirement>: <n>/<N> postings — gap\n\nRed lines\n  \"<pattern>\": fired <n>× — <k> OUT, <m> CONDITIONAL\n\nYour two dimensions\n  Desirability: <n> Strong · <n> Good · <n> Weak · <n> Poor\n  Candidacy:    <n> Likely · <n> Plausible · <n> Stretch\n  Both high: <n>   ← the roles actually worth your time\n\nOutcomes (of <n> entries with Outcome filled)\n  <action tier>: applied <n>, interviewing <n>, rejected <n>, offer <n>\n\n💡 <2-4 observations, each traceable to a number above>\n```\n\n### Rules\n\n- **Group by the user's own vocabulary.** Bucket organizations using their\n  `org_traits`, not a taxonomy of your own. Anything that fits none is\n  `unclassified` — a large unclassified count is itself the finding, and means\n  their trait list is missing something.\n- **Requirement demand** is counted from stored requirement text across entries,\n  cross-referenced with `skills`. Rank by `frequency × (1 − credit)`: something\n  asked for constantly that the user is halfway through learning outranks\n  something rarer they have not started.\n- **Red-line review.** If a red line has fired ≥ 3 times and *never* produced an\n  OUT — only CONDITIONAL — say so and offer to demote it to a negative vibe\n  anchor. It is behaving like a preference, not a gate.\n  If a red line has never fired at all across ≥ 15 entries, mention it once;\n  it may be aimed at postings the user is not even seeing.\n- **Calibration, only with outcomes.** If ≥ 5 entries have an `Outcome`, compare\n  predicted Candidacy against what happened. Report it flatly:\n  *\"Of 6 rated Stretch, 3 got a first interview — the Candidacy read may be\n  running pessimistic.\"* Fewer than 5 → skip the section entirely, do not hedge\n  a guess.\n- **Never infer market conditions.** The sample is the user's inbox, not the job\n  market. Say \"the roles reaching you\", never \"the market is\".\n\n---\n\n## `/jd-triage plan`\n\nPer target role:\n\n```\n🎯 <role name>\n   Based on <n> matching postings in your history\n\nRequirements this role asks for\n   ✅ <requirement>            you have it — <n>/<N> postings asked\n   ⚠️ <requirement>            learning — <n>/<N> asked\n   ❌ <requirement>            gap — <n>/<N> asked\n\nNext, in order\n   1. <item> — asked in <n>/<N> postings, you're already partway\n   2. <item> — asked in <n>/<N>, not started\n   3. <item> — rarer, but blocks the roles you rated highest\n\nEvidence to build\n   <item>: <one concrete artifact that would let you claim it in an interview>\n```\n\n### Ranking\n\nOrder by demand × proximity: frequency in matching postings, weighted up for\nitems already in `skills.learning` (finishing beats starting), weighted down for\nitems appearing only in `preferred` sections.\n\nSay plainly when an item is low-frequency but appears in the highest-desirability\npostings — that is a different kind of bet and the user should make it knowingly.\n\n### Evidence suggestions\n\nOne per gap, concrete and checkable — something that produces an artifact a\nrecruiter or interviewer can look at. A shipped thing, a written thing, a\nmeasured thing. Never suggest a course as the artifact; a certificate is not\nevidence of the skill.\n\n### What this command does not do\n\n- **No timelines.** Do not estimate months to close a gap. You do not know the\n  user's available hours, and a fabricated schedule is worse than none. If they\n  ask, ask how much time per week they actually have and reason from that.\n- **No aptitude judgments.** Rank by market demand and proximity, never by\n  whether the user seems capable of something.\n- **No scope creep into career advice.** This command closes named gaps against\n  named roles. Whether the target role is the right target is a different\n  conversation, and it belongs to the user.\n\nFile v1.1.0:references/bootstrap.md\n\n# Bootstrap\n\nThree ways in. Default to **Quick Start** — a profile that exists is worth more\nthan a perfect profile the user abandoned halfway through.\n\n| Mode | When | Cost |\n|---|---|---|\n| **Quick Start** | S1 (no file), `/jd-triage quickstart` | 5 questions |\n| **Derive from examples** | `/jd-triage learn`, or offered when a profile is thin | Paste a few JDs |\n| **Full** | S5 (`update` / `reset`), or user asks | All fields |\n\nWrite to `~/.openclaw/workspace/jd_criteria.md` using `assets/criteria-template.yaml`.\nField keys English; values in the user's language.\n\n## Using presets\n\n`assets/presets/*.yaml` are **menus, never defaults**. Pick the preset matching\nthe user's `role_family`, show the suggested traits and red-line starters as a\nnumbered list, and write only the lines the user selects — reworded however they\nlike. Never silently write a preset value. `axis_weights` are the one exception:\nthey are a starting distribution, applied unless the user changes them, and\nmentioned once so the user knows they exist.\n\n---\n\n## Quick Start — 5 questions\n\nAsk one at a time. Accept \"skip\" on any of them.\n\n**1. Context.** \"What kind of role, what market, and which languages can you work\nin?\" → `context.role_family`, `context.market`, `context.languages`.\nFrom the market, infer `context.comp_convention` and **state the inference for\nconfirmation** (\"I'll assume comp is quoted as an all-in annual number — correct?\").\n\n**2. Target.** \"What titles are you looking for, and what should the organization\nactually do?\" → `soft_axes.target_title_keywords`, `soft_axes.target_domains`.\n\n**3. Floors.** \"What's the lowest offer you'd accept — and is that base or\nall-in? Where can you work, and is remote acceptable?\" → `hard_gates.comp_floor`\n(amount, currency, period, basis), `hard_gates.locations`, `hard_gates.remote_ok`.\n\n**4. Automatic no's.** \"Anything that makes a role an instant no — and why?\"\n→ `hard_gates.red_lines`. Push for the *why* on each one; it is what makes\nmatching work across languages and rewordings. \"None\" is a valid answer.\n\n**5. Anchors.** Use the preset's `vibe_prompt`. Ask for 1–3 organizations, teams,\nor products the user admires, **each with one line on why**.\n→ `soft_axes.vibe_anchors_positive`.\n\nThen write the file and say plainly what is not yet filled:\n\n> Saved. Org fit and Candidacy will show *info insufficient* until you add org\n> traits and your skills — I'll ask for those the first time they matter.\n\n### Just-in-time capture\n\nDo not front-load the rest. Ask for a field the first time an evaluation\nactually needs it, once, inline:\n\n- **Skills** — before scoring Candidacy for the first time: \"To score whether you\n  can get this, I need your skills. List what you could be interviewed on today,\n  and separately what you're actively learning.\" → `skills.mastered`,\n  `skills.learning`. Write them to the file so this is asked only once.\n- **Org traits** — the first time a JD's org type looks decision-relevant.\n- **Negative anchors** — the first time a JD trips something the user reacts badly\n  to: \"Want me to save that as a negative anchor?\"\n- **Intensity tier** — the first time a JD carries strong intensity signals.\n\nEach capture writes to the file and bumps `criteria_version`.\n\n---\n\n## Derive from examples (`/jd-triage learn`)\n\nThe highest-quality path, and the repair path for a thin or lazy profile. People\nare bad at stating preferences in the abstract and good at reacting to concrete\npostings.\n\n1. Ask for **2–4 postings the user would apply to** and **2–4 they turned down or\n   scrolled past**. Past rejections work; so do screenshots pasted as text.\n2. Read all of them and extract:\n   - Recurring title and scope patterns → `target_title_keywords`\n   - What the organizations do → `target_domains`\n   - Traits shared by the liked set / by the rejected set → `org_traits`\n   - Phrases that plausibly explain each rejection → candidate `red_lines`\n   - Tone and values language distinguishing the two sets → candidate anchors\n3. **Propose, never write.** Output a numbered list of drafted entries, each with\n   the evidence it came from and a drafted `why`:\n\n   ```\n   3. Red line: \"individual revenue target\"\n      From: Posting B, \"own a quarterly booking number\" — you skipped this one.\n      Why (draft): a quota changes what the job optimizes for.\n      Keep / edit / drop?\n   ```\n4. Write only accepted items. Ask the user to fix any `why` that does not sound\n   like them — the `why` is what the skill reasons from later.\n\nNever infer a red line from a single posting without saying which one it came\nfrom. One rejection can have many causes; the user picks the real one.\n\n---\n\n## Full bootstrap\n\nEvery field in `assets/criteria-template.yaml`, in four blocks, one block per\nturn. Pre-fill current values on S5 so the user only changes what moved.\n\n**Block 1 — Context & profile**\n`context` (role_family, market, languages, comp_convention, fx_rates if the user\ncompares currencies) · `profile` (years_of_experience, current_title_org,\ncurrent_comp with basis and notes)\n\n**Block 2 — Hard gates**\n`comp_floor` (with basis) · `locations` · `remote_ok` · `intensity_tier` ·\n`red_lines` (each with a `why`)\n\n**Block 3 — Soft axes**\n`target_title_keywords` · `target_domains` · `org_traits` (trait + weight 1–5) ·\n`vibe_anchors_positive` and `vibe_anchors_negative` (each with a `why`) ·\n`axis_weights` (offer the current distribution, ask only if they want to change it)\n\n**Block 4 — Skills & targets**\n`skills.mastered` / `.learning` / `.want_to_learn` · `target_roles`\n\nState the half-credit rule when asking for skills: `learning` items score 0.5\nagainst a requirement, so an honest split produces better advice than an\noptimistic one.\n\n### Summary and confirm\n\nShow everything grouped as above, then:\n\n```\nConfirm and save?  (y / edit <field>)\n```\n\n`edit <field>` re-asks that field only, then re-shows the summary. On `y`, write\nthe file with today's ISO date and an incremented `criteria_version`.\n\n---\n\n## Migration\n\nTriggered by S2 (`schema_version` < 3). Migrate everything inferable **without\nasking**, then ask only for what cannot be derived. Show a summary of what\nchanged before writing.\n\n| Old (v1 / v2) | New (v3) | How |\n|---|---|---|\n| `hard_gates.salary_floor` (string) | `hard_gates.comp_floor` (structured) | Parse amount / currency / period. **Basis cannot be inferred — ask.** Show the parse for confirmation |\n| `profile.current_salary` (string) | `profile.current_comp` (structured) | Same; keep anything unparseable in `notes` verbatim |\n| `lifestyle_tier` | `intensity_tier` | `strict_9to5`→`strict_hours`, `standard`→`standard`, `crunch`→`high`, `always_on`→`always_on` |\n| `target_cities` | `hard_gates.locations` | Copy. If `Remote` was in the list, set `remote_ok: yes` and drop it from locations |\n| `target_industries` | `soft_axes.target_domains` | Copy. Flag entries that describe an org *type* rather than a domain and offer to move them to `org_traits` |\n| `company_type_preferences` + `company_size_preferences` | `soft_axes.org_traits` | Each entry rated ≠ 3 becomes `{trait, weight}`. **Entries rated 3 are dropped** — they never changed any outcome. Say how many were dropped |\n| `hard_red_lines` (strings) | `hard_gates.red_lines` (`{pattern, why}`) | Pattern copies over; **`why` must be asked** — it is what enables semantic matching |\n| `vibe_anchors_positive` / `_negative` (strings) | same keys, `{name, why}` | Names copy over; **`why` must be asked.** Without it the skill can only reason from what it happens to know about that organization, which is exactly the failure mode v3 fixes |\n| `skills`, `target_roles`, `learning_velocity` (v2 only) | unchanged | Copy verbatim |\n| — | `context` | **Ask** — nothing in v1/v2 implies market or comp convention |\n| — | `axis_weights` | Apply defaults, mention once |\n\nSo a migration asks for, at most: comp basis, one `why` per red line and anchor,\nand the `context` block. Batch them into a single turn.\n\nIf `red_lines` is empty after migration, say so directly — it means the\nresponsibility-weighting logic has never had anything to act on — and offer\n`/jd-triage learn` to populate it from real postings.\n\nFile v1.1.0:references/history.md\n\n# History\n\n`~/.openclaw/workspace/jd_history.md` — a single append-only log. Create it on the first\nevaluation.\n\n**Every evaluation writes an entry, including OUT.** Rejections are the most\nuseful rows in the file: they are what `analyze` reads to tell the user which\npattern keeps landing in their inbox. An evaluation that produced no entry did\nnot finish — say so rather than letting it pass.\n\n## Language\n\nStructural labels are **always English** (`Evaluated`, `Action`, `Desirability`,\n`Candidacy`, `Scores`, `Summary`, `Triggered`, `Outcome`, `Criteria version`) so\nthe file stays greppable when the user switches languages.\n\nFree text — org name, title, summary, red-line citations, JD quotes — is stored\nin the language it was written in and **never retroactively translated**. Listing\nand comparison output renders labels in the current language and shows stored\ntext verbatim.\n\n## ID\n\n`JD-YYYYMMDD-NNN` — today's date, then a per-day sequence starting at `001`,\nfound by grepping existing entries with the same date prefix.\n\n## Entry — standard detail\n\n```markdown\n## [JD-20260725-001] <org> — <title>\n\n**Evaluated**: 2026-07-25\n**Criteria version**: 4\n**Action**: ✅ Apply\n**Desirability**: Good (3.6/5)\n**Candidacy**: Plausible (70%)\n\n### Scores\n- Role fit:  ★★★★☆\n- Domain:    ★★★★★\n- Org:       — (info insufficient)\n- Vibe:      ★★★☆☆\n- Comp:      ★★★★☆\n\n### Candidacy\nMeets 3.5/5 stated must-haves. Gaps: team management, Kubernetes (learning).\n\n### Summary\n<one line>\n\n### Triggered\n<red lines or failed gates with location, or \"none\">\n\n### Outcome\n<blank — the user fills this in later: applied / rejected / interviewing / offer / passed>\n```\n\n`minimal` — the heading, `Evaluated`, `Action`, `Summary`.\n\n`full` — adds a `### Raw JD` block. **Warn once before the first `full` write:**\n\"This stores the complete posting, which may include recruiter contact details or\ncomp not published elsewhere. Continue? (y/n)\". Do not re-ask on later writes.\n\n## OUT entries\n\nShorter body: no `Scores` or `Candidacy` sections — scoring stopped at the gate.\nKeep `Triggered` and `Summary`, and record the \"Matched anyway\" points under\n`Summary` so the signal is not lost.\n\n## The Outcome field\n\nLeft blank by the skill. If the user mentions an outcome in conversation\n(\"I applied to the Figma one\", \"they rejected me\"), offer to fill it in — never\nwrite it silently. Outcomes are what let `analyze` compare *predicted* fit with\n*actual* results; a file with none is still useful, just blind to that.\n\n## `/jd-triage history`\n\nLast 10 entries, one line each, newest last:\n\n```\nJD-20260712-001  Basecamp     Senior PM        ✅ Apply        Good/Plausible    applied\nJD-20260718-002  Northvolt    Product Lead     🗄️ Backup       Weak/Likely       —\nJD-20260725-001  Figma        PM, Dev Tools    🔥 Apply now    Strong/Plausible  —\n```\n\nSupport a filter argument: `/jd-triage history apply` shows only Apply-tier\nactions; `/jd-triage history out` only OUT.\n\n## `/jd-triage compare <id1> [<id2>]`\n\nTwo IDs, or one ID against the most recent, or \"the last two\".\n\n```\n                  JD-20260718-002        JD-20260725-001\n                  Northvolt              Figma\n                  Product Lead           PM, Dev Tools\n                  ──────────────         ──────────────\nAction            🗄️ Backup              🔥 Apply now\nDesirability      Weak (2.8)             Strong (4.2)\nCandidacy         Likely (85%)           Plausible (60%)\nCriteria version  4                      4\nRole fit          ★★★☆☆                  ★★★★★\nDomain            ★★☆☆☆                  ★★★★★\nOrg               ★★★★☆                  — (insufficient)\nVibe              ★★★☆☆                  ★★★★☆\nComp              ★★★★☆                  ★★★★☆\n\n<one line: which is stronger, and the trade the user is actually making>\n```\n\nThe closing line must name the trade-off rather than declare a winner — these two\ndiffer on *both* dimensions in opposite directions, which is the entire point of\nkeeping them apart.\n\n**Criteria drift warning.** If the two entries used different `Criteria version`\nvalues, prepend:\n\n```\n⚠️ Your criteria changed between these evaluations (v4 → v6).\n   Axes touched by the change are not directly comparable.\n```\n\nName which axes moved if the current file makes that determinable.\n\n## Growth\n\nThe file grows without bound by design — `analyze` gets better with more rows.\nIf it passes roughly 100 entries and the user asks, offer to archive entries\nolder than a year to `jd_history_<year>.md` rather than deleting them. Never\ndelete history unprompted.\n\nFile v1.1.0:references/intensity-signals.md\n\n# Intensity signals\n\nMaps job-posting language to `intensity_tier` for the hard gate. Load this when\nthe posting is not in English, or when its intensity is ambiguous.\n\nTiers, in order: `strict_hours` < `standard` < `high` < `always_on`.\nThe gate fails when the **JD's implied tier exceeds the user's**.\n\n## How to use it\n\n1. Scan the posting — including the benefits and culture sections, where the\n   strongest signals usually hide.\n2. Take the **highest** tier any matched phrase implies.\n3. No signal in either direction → assume the user's own tier, apply no penalty,\n   and say the posting was silent on it.\n4. A posting can carry signals from two tiers (\"flexible hours\" *and* \"on-call\n   rotation\"). Report both and take the higher; the contradiction itself is worth\n   an open question.\n\nPhrases below are indicative, not exhaustive — match meaning, not strings.\n\n## English\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"no overtime\", \"we don't work weekends\", \"core hours\", \"35-hour week\", \"strict work-life boundaries\", \"right to disconnect\" |\n| `standard` | \"occasional crunch around launches\", \"some evenings during release weeks\", \"fast-paced but sustainable\" |\n| `high` | \"fast-paced environment\", \"wear many hats\", \"hustle\", \"long hours\", \"whatever it takes\", \"we work hard and play hard\", \"comfortable with ambiguity and pace\", early-stage with no counterweight language |\n| `always_on` | \"on-call rotation\", \"24/7 coverage\", \"follow the sun\", \"global team across time zones\" with meetings outside local hours, \"always-on culture\" |\n\n## Chinese\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"不加班\", \"准时下班\", \"弹性工作\", \"双休\" with explicit no-overtime language |\n| `standard` | \"偶尔加班\", \"项目期加班\", \"节奏快但可持续\" |\n| `high` | \"高强度\", \"抗压能力强\", \"能接受加班\", \"创业心态\", \"狼性\", \"全力以赴\" |\n| `always_on` | \"996\", \"大小周\", \"单休\", \"7×12\", \"随时响应\", \"on-call 轮值\" |\n\n## Japanese\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"残業なし\", \"定時退社\", \"フレックス\", \"ワークライフバランス重視\" |\n| `standard` | \"繁忙期のみ残業あり\", \"月20時間程度の残業\" |\n| `high` | \"裁量労働制\" without stated caps, \"みなし残業\" with a high included-hours figure, \"ベンチャーマインド\", \"成長意欲の高い方\" |\n| `always_on` | \"オンコール\", \"24時間体制\", \"深夜対応あり\", \"サービス残業\" |\n\n## German\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"keine Überstunden\", \"Gleitzeit\", \"35-Stunden-Woche\", \"Vertrauensarbeitszeit\" with stated limits, \"Work-Life-Balance\" |\n| `standard` | \"gelegentliche Überstunden\", \"in Projektphasen\" |\n| `high` | \"hohe Belastbarkeit\", \"Hands-on-Mentalität\", \"dynamisches Umfeld\", \"Start-up-Mentalität\" |\n| `always_on` | \"Rufbereitschaft\", \"24/7-Support\", \"Schichtdienst\" |\n\n## French\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"35 heures\", \"droit à la déconnexion\", \"horaires fixes\", \"équilibre vie pro/vie perso\" |\n| `standard` | \"quelques pics d'activité\", \"heures supplémentaires occasionnelles\" |\n| `high` | \"forte capacité de travail\", \"environnement exigeant\", \"esprit start-up\", \"polyvalence\" |\n| `always_on` | \"astreinte\", \"support 24/7\", \"disponibilité permanente\" |\n\n## Spanish\n\n| Tier | Signals |\n|---|---|\n| `strict_hours` | \"jornada intensiva\", \"horario flexible\", \"sin horas extra\", \"conciliación\" |\n| `standard` | \"picos de trabajo puntuales\", \"horas extra ocasionales\" |\n| `high` | \"alta capacidad de trabajo\", \"ambiente exigente\", \"mentalidad startup\", \"resistencia a la presión\" |\n| `always_on` | \"guardias\", \"disponibilidad 24/7\", \"turnos rotativos\" |\n\n## Other languages\n\nReason from meaning using the tier definitions in\n`assets/criteria-template.yaml`, and state that you inferred rather than matched.\nIf the user confirms or corrects your reading, offer to append the phrase to this\nfile's table for their language so the next posting matches directly.\n\n## Watch for\n\n- **Benefits sections that contradict the duties.** \"Unlimited PTO\" next to\n  \"always available for our global customers\" is an `always_on` signal wearing a\n  `strict_hours` costume. Report the contradiction.\n- **Compensation structures implying hours** — a large \"included overtime\"\n  allowance, or a base that assumes on-call pay, implies `high` or above whatever\n  the culture section says.\n- **Silence in markets where hours are regulated.** In markets with statutory\n  limits, no mention of hours is weak evidence of `standard`, not of\n  `strict_hours`. Do not upgrade a posting on silence alone.\n\nFile v1.1.0:references/scoring.md\n\n# Scoring\n\nTwo dimensions, computed separately, never averaged together. Decision tiers and\nthe action matrix live in `SKILL.md § Decide` — this file defines how each number\nis produced.\n\n## Rules that apply to every axis\n\n- **1–5 only. No 3★ placeholders.** If the JD does not contain the information an\n  axis needs, output `(info insufficient)` and drop the axis from the average.\n- **Cite the JD.** Every score below 4★ or above 4★ names the phrase that drove\n  it. Quote the JD in its original language even when the surrounding output is\n  translated — a translated quote is no longer evidence.\n- **The criteria file is the only source of preference.** Never score against what\n  you happen to know about an industry, a city, or an employer's reputation.\n\n---\n\n## Desirability axes\n\n### Role fit — `target_title_keywords`, plus scope and seniority in the body\n\n| ★ | Meaning |\n|---|---|\n| 5 | Title matches a keyword, and the responsibilities match what the user means by that title |\n| 4 | Title clearly aligns, or matches with a different label but the same substance |\n| 3 | Adjacent — same family, different specialty, or a level off |\n| 2 | Related only through a shared word; the actual work is something else |\n| 1 | No match |\n\nRead the bullets, not just the header. The same title means different work at\ndifferent organizations — a title match with mismatched responsibilities is a\n3★, not a 5★, and the one-liner should say so.\n\n### Domain fit — `target_domains`\n\n| ★ | Meaning |\n|---|---|\n| 5 | The organization's main business is in the user's list |\n| 4 | In the list, but this role sits on an adjacent product or team |\n| 3 | One step removed — the domain is applied to a field the user did not ask for |\n| 2 | Tangential |\n| 1 | Not in the list |\n\n**Match by meaning, not by label.** The user wrote their domains in their own\nwords; a posting will use different ones. \"Forecasting and settlement software for\nregional grid operators\" *is* climate tech, and \"cohort-building tools for hospital\nresearch teams\" *is* health data, even though neither phrase appears in the list.\nName which listed domain you matched it to and why, so a wrong reading is visible\nand correctable. Reserve 1★ for a genuine miss, not a vocabulary mismatch.\n\n### Org fit — `org_traits`\n\nIdentify which of the user's traits this organization plausibly has, from the JD\nand its self-description only. Traits you cannot assess are simply not matched —\ndo not assume.\n\n| Situation | Score |\n|---|---|\n| One or more traits present | Weighted mean of the **present** traits' weights |\n| Traits were assessable, none of them present | **3★** — neutral |\n| Nothing about the organization can be assessed | `(info insufficient)` |\n\n**The absence of a preferred trait is not the presence of a rejected one.** An\nemployer that is merely *not* remote-first and *not* a research lab scores 3★, not\n1★. A low score requires a trait the user weighted 1–2 to actually be there — a\nposting that says \"a Thornbury Capital portfolio company\" against a stored\n`private-equity owned: 1` earns the 1★; a posting that simply never mentions\nownership does not.\n\nAn unknown employer with no self-description is the normal case, not a failure.\n\n### Vibe fit — `vibe_anchors_positive` / `vibe_anchors_negative`\n\nThe axis people rationalize away and then regret. Compare the JD's language,\nvalues statements, and product description against the anchors — **reasoning from\neach anchor's `why`, not from the anchor's reputation.**\n\n| ★ | Meaning |\n|---|---|\n| 5 | Multiple signals matching a positive anchor's `why`; nothing matching a negative one |\n| 4 | Clear positive-anchor alignment, no negative signals |\n| 3 | Genuinely neutral — the JD is written in standard corporate register and reveals little |\n| 2 | Some language matching a negative anchor's `why` |\n| 1 | Strong, repeated match to a negative anchor's `why` |\n\n**Mandatory citation format:**\n\n```\nVibe ★★☆☆☆  negative anchor \"<name>\" — its why: \"<the user's stated reason>\"\n            triggered by: \"<exact JD phrase>\", \"<exact JD phrase>\"\n```\n\nAn adjective without a quote is not a rating. \"Feels corporate\", \"seems\ngrowth-y\", \"no product taste\" are all invalid on their own.\n\n**Unknown organizations.** If you have no reliable knowledge of an anchor, that\nchanges nothing: the `why` is the comparison basis, and it always was. Never\nsubstitute a reputation for the user's stated reason — that is how the axis drifts\naway from the person it is supposed to represent. Equally, never refuse to score\nbecause an anchor is obscure.\n\n### Comp fit — `comp_floor`, `profile.current_comp`\n\nCompare **like for like** first. Normalize period (year / month / hour) and check\n`basis`:\n\n- JD quotes base, floor is `total` → not comparable. Mark `(info insufficient)`\n  and raise an open question asking for the full package.\n- Different currencies → convert only with a rate from `context.fx_rates`.\n  Without one, mark `(info insufficient)`. **Never invent an exchange rate.**\n- `context.comp_convention: n_month` → annualize using the stated multiplier\n  before comparing, and show the arithmetic.\n\n| ★ | Meaning |\n|---|---|\n| 5 | ≥ 130% of current comp |\n| 4 | 110–129% |\n| 3 | 100–109% — lateral |\n| 2 | Below current but at or above the floor |\n| 1 | Below the floor — the hard gate should already have caught this |\n\nNo comp stated in the JD → `(info insufficient)` plus an open question. This is\nthe most common case in many markets; it must not silently become a 3★.\n\n---\n\n## Combining the desirability axes\n\nWeighted mean using `axis_weights`. Axes marked `(info insufficient)` are removed\nand the remaining weights renormalized.\n\nWorked example — Org fit and Comp fit both unavailable:\n\n```\nRole fit  4  weight 25\nDomain    5  weight 20\nOrg       —  (info insufficient, dropped)\nVibe      2  weight 25\nComp      —  (info insufficient, dropped)\n\nRemaining weight = 25 + 20 + 25 = 70\nWeighted = (4×25 + 5×20 + 2×25) / 70 = (100 + 100 + 50) / 70 = 3.57\nDesirability tier: Good  →  capped at Weak by the vibe ≤ 2★ rule\n```\n\nShow the renormalized denominator whenever an axis was dropped, so the user can\nsee the verdict rests on three axes rather than five.\n\nIf **three or more** axes are insufficient, do not report a tier. Say the posting\nis too thin to score and list what to ask for.\n\n---\n\n## Candidacy\n\n### Extract the requirements\n\nSplit the JD's requirements into **must-have** and **preferred**. Markers vary by\nlanguage and market; treat anything hedged — preferred, nice to have, a plus,\nbonus, ideally, 优先, wünschenswert, 尚可 — as preferred.\n\nAmbiguous section with no split marker → treat everything as must-have and note\nthe assumption.\n\n### Score\n\n| Requirement matches | Credit |\n|---|---|\n| an item in `skills.mastered` | 1.0 |\n| an item in `skills.learning` | 0.5 |\n| nothing | 0 |\n\nYears of experience is one requirement, met if `profile.years_of_experience` is\nwithin one year of the stated minimum. A stated maximum is not a requirement.\n\n`hit_rate = credit_earned / count(must_have)`\n\n| Tier | Hit rate |\n|---|---|\n| **Likely** | ≥ 75% |\n| **Plausible** | 40–74% |\n| **Stretch** | < 40% |\n| **Unknown** | fewer than 3 stated must-haves |\n\nWorked example:\n\n```\nMust-haves (5):\n  5+ years in the field          → profile says 6         1.0\n  SQL                            → mastered               1.0\n  Experiment design              → mastered               1.0\n  Kubernetes                     → learning               0.5\n  Managed a team of 3+           → no match               0\n\ncredit 3.5 / 5 = 70%  →  Plausible\nPreferred (not counted): German at C1, healthcare experience\n```\n\n### Reporting rules\n\n- **Count only what the JD states.** Never add a requirement the posting does not\n  contain, however standard it seems for the role.\n- **Never map seniority across markets.** L5, P7, Senior II, 主管, and Grade 6 are\n  not comparable. Count stated requirements; ignore the level label.\n- **Report gaps as facts plus context**, e.g. *\"No team-management evidence — this\n  is usually probed with 'tell me about a time you gave difficult feedback', so\n  it is answerable from mentoring experience if you have any.\"* Not a verdict on\n  the person.\n- **No inflation.** Do not round `learning` up to `mastered` because the user\n  seems close. The half-credit exists so the honest answer is the useful one.\n- **No catastrophizing.** A Stretch is a real option with a named gap, not a\n  rejection. Say which one or two items would move it to Plausible.\n- Preferred requirements the user *does* meet are worth mentioning — they are\n  interview material even though they do not affect the tier.\n\nFile v1.1.0:skill-card.md\n\n## Description: <br>\nScores pasted job postings on separate desirability and candidacy dimensions against a user's stored criteria, then returns a concrete action and logs the evaluation. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[bwancoding](https://clawhub.ai/user/bwancoding) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nJob seekers use this skill to evaluate a posting or recruiter message against their own criteria, separating whether they want the role from whether they meet its stated requirements. It also supports criteria setup, history review, role comparison, trend analysis, and gap planning over accumulated evaluations. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill keeps local job-search preferences, compensation preferences, skills, and evaluation history, and full raw-JD history can include recruiter messages or contact details. <br>\nMitigation: Use standard history unless raw posting text is needed, avoid full history in synced or shared workspaces, and review the local Markdown files before sharing them. <br>\nRisk: Future recommendations depend on the user's stored criteria and skills inventory, so stale or malformed profile data can skew verdicts. <br>\nMitigation: Review and update jd_criteria.md when preferences or skills change, and answer the skill's clarification prompts instead of letting uncertain fields stand. <br>\n\n\n## Reference(s): <br>\n- [ClawHub Skill Page](https://clawhub.ai/bwancoding/skills/jd-triage) <br>\n- [Criteria Template](assets/criteria-template.yaml) <br>\n- [Bootstrap Reference](references/bootstrap.md) <br>\n- [Scoring Reference](references/scoring.md) <br>\n- [History Reference](references/history.md) <br>\n- [Analyze and Plan Reference](references/analysis-commands.md) <br>\n- [Intensity Signals Reference](references/intensity-signals.md) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, configuration, guidance] <br>\n**Output Format:** [Markdown verdicts and local Markdown criteria/history files] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Outputs keep desirability and candidacy separate, preserve user-language free text, and may append evaluation history under ~/.openclaw/workspace.] <br>\n\n## Skill Version(s): <br>\n1.1.0 (source: server release evidence) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nFile v1.1.0:assets/criteria-template.yaml\n\n# jd_criteria.md — schema v3\n#\n# Written to ~/.openclaw/workspace/jd_criteria.md by the jd-triage skill.\n# Field keys are English and machine-readable. Values are in whatever language\n# you wrote them in, and are never auto-translated.\n#\n# Hand-editing is expected and supported. The skill parses what it finds and\n# asks about anything malformed rather than overwriting it.\n\nschema_version: 3\ncriteria_version: 1\nlast_updated:                 # ISO-8601, e.g. 2026-07-25\n\nhistory_detail: standard      # minimal | standard | full\n                              #   minimal  — org, title, action, date\n                              #   standard — + both dimensions, scores, one-liner (default)\n                              #   full     — + raw JD text (may contain recruiter contact\n                              #              details or unposted comp; you are warned once)\n\n# ─────────────────────────────────────────────────────────────\n# Context — establishes the vocabulary for everything below.\n# Fill this first: it tells the skill which market conventions,\n# comp structures, and intensity signals apply to you.\n# ─────────────────────────────────────────────────────────────\ncontext:\n  role_family:                # free text, e.g. \"product management\",\n                              # \"backend engineering\", \"brand design\",\n                              # \"clinical research\", \"policy\"\n  market:                     # where you are looking, e.g. \"Germany\",\n                              # \"US remote\", \"mainland China tech\", \"Japan\"\n  languages: []               # languages you can work in, e.g. [\"English\", \"German\"]\n  comp_convention:            # how comp is normally quoted where you are looking:\n                              #   total          — one all-in number\n                              #   base_plus_var  — base + bonus and/or equity, quoted separately\n                              #   n_month        — annual = monthly × N (e.g. 13th/14th month)\n                              #   hourly | daily — contract / freelance\n  fx_rates: {}                # optional, only if you compare across currencies,\n                              # e.g. {USD_per_EUR: 1.08}. The skill will not\n                              # invent a rate; without one it flags the mismatch.\n\n# ─────────────────────────────────────────────────────────────\n# Profile — you, right now\n# ─────────────────────────────────────────────────────────────\nprofile:\n  years_of_experience:        # integer\n  current_title_org:          # free text, e.g. \"PM @ Acme\"\n  current_comp:\n    amount:                   # number\n    currency:                 # ISO code, e.g. USD, EUR, CNY, JPY\n    period:                   # year | month | hour\n    basis:                    # total | base\n    notes:                    # anything the numbers do not capture,\n                              # e.g. \"14 months\", \"+ RSU ~15%\", \"pre-tax\"\n\n# ─────────────────────────────────────────────────────────────\n# Skills — the input to the Candidacy dimension.\n# Be honest about the split: `learning` items score half credit,\n# so inflating `mastered` only produces worse advice.\n# ─────────────────────────────────────────────────────────────\nskills:\n  mastered: []                # you could be interviewed on this today\n  learning: []                # actively building; half credit toward requirements\n  want_to_learn: []           # not started; used by `plan`, not by scoring\n\n# ─────────────────────────────────────────────────────────────\n# Target roles — archetypes you are aiming at. Drives `plan`.\n# ─────────────────────────────────────────────────────────────\ntarget_roles: []\n  # - id: short_slug\n  #   name: \"Human-readable role name\"\n  #   description: \"What this role actually does, in your words\"\n\n# ─────────────────────────────────────────────────────────────\n# Hard gates — a failure ends the evaluation (red lines are weighted)\n# ─────────────────────────────────────────────────────────────\nhard_gates:\n  comp_floor:\n    amount:\n    currency:\n    period:                   # year | month | hour\n    basis:                    # total | base — compared like-for-like against the JD\n  locations: []               # e.g. [\"Berlin\", \"Amsterdam\"]\n  remote_ok:                  # yes | no | hybrid_only\n  intensity_tier:             # strict_hours | standard | high | always_on\n                              #   strict_hours — fixed hours, evenings and weekends off\n                              #   standard     — occasional crunch around releases\n                              #   high         — long hours normal, some weekends expected\n                              #   always_on    — on-call, cross-timezone, no clear boundary\n  red_lines: []               # matched semantically, then weighted by where it sits\n                              # in the JD. The `why` is what makes cross-language and\n                              # reworded matches work — do not omit it.\n  # - pattern: \"revenue ownership\"\n  #   why: \"I do not want a quota; it changes what the job optimizes for\"\n  # - pattern: \"on-call rotation\"\n  #   why: \"health reasons, non-negotiable\"\n\n# ─────────────────────────────────────────────────────────────\n# Soft axes — scored 1-5 per JD, combined using axis_weights\n# ─────────────────────────────────────────────────────────────\nsoft_axes:\n  target_title_keywords: []   # titles you want to see in the header\n  target_domains: []          # what the org does, e.g. [\"developer tools\",\n                              # \"public health\", \"climate hardware\"]\n\n  org_traits: []              # replaces fixed company-type/size enums: describe\n                              # traits in your own words and weight them 1-5\n                              # (1 = actively avoid, 5 = strongly prefer)\n  # - trait: \"research lab with a shipping product\"\n  #   weight: 5\n  # - trait: \"private-equity owned\"\n  #   weight: 1\n  # - trait: \"under 50 people\"\n  #   weight: 2\n\n  vibe_anchors_positive: []   # organizations, teams, or products you admire.\n                              # `why` is mandatory and load-bearing: it is what\n                              # lets the skill reason about an org it has never\n                              # heard of, and what keeps it from inventing a\n                              # reputation for one it has.\n  # - name: \"Linear\"\n  #   why: \"restraint — a clear product opinion, no feature-count race\"\n\n  vibe_anchors_negative: []   # same shape; energy you actively avoid\n  # - name: \"<a place you left>\"\n  #   why: \"manufactured urgency, metrics used as a loyalty test\"\n\n# ─────────────────────────────────────────────────────────────\n# Axis weights — must sum to 100. Axes with insufficient\n# information drop out and the rest are renormalized.\n# ─────────────────────────────────────────────────────────────\naxis_weights:\n  role_fit: 25\n  domain_fit: 20\n  org_fit: 15\n  vibe_fit: 25\n  comp_fit: 15\n\nFile v1.1.0:assets/presets/knowledge-work.yaml\n\n# Preset: profession-neutral knowledge work\n# (consulting, research, policy, marketing, operations, finance, legal, education)\n#\n# Use this when no other preset fits, or when the user's field is outside tech.\n# A preset is a MENU, not a default. Offer these lines, let the user pick and\n# reword, and write only what they chose.\n\npreset_id: knowledge-work\nlabel: \"Knowledge work — general\"\n\nsuggested_org_traits:\n  - \"mission-driven or nonprofit\"\n  - \"public sector or government\"\n  - \"academic or research institution\"\n  - \"professional services firm\"\n  - \"family-owned or founder-controlled\"\n  - \"publicly traded\"\n  - \"heavily regulated industry\"\n  - \"under 50 people\"\n  - \"international, English-speaking office\"\n\nsuggested_red_line_starters:\n  - \"billable-hours target\"\n  - \"significant travel required\"\n  - \"fixed on-site five days a week\"\n  - \"individual sales or fundraising quota\"\n  - \"rotating shifts\"\n\nvibe_prompt: >\n  Name 1-3 organizations or teams you would be glad to work in — any sector, any\n  size, including ones only people in your field would recognize. One line each\n  on WHY. The reason is what the skill actually reasons from.\n\naxis_weights:\n  role_fit: 25\n  domain_fit: 20\n  org_fit: 15\n  vibe_fit: 25\n  comp_fit: 15\n\nFile v1.1.0:assets/presets/people-lead.yaml\n\n# Preset: manager / lead track (any function)\n#\n# A preset is a MENU, not a default. Offer these lines to the user during Quick\n# Start, let them pick and reword, and write only what they chose. Never write a\n# preset value into jd_criteria.md without the user selecting it.\n\npreset_id: people-lead\nlabel: \"Manager / lead track\"\n\nsuggested_org_traits:\n  - \"flat org, few management layers\"\n  - \"team already exists (not a hire-from-zero mandate)\"\n  - \"budget authority for the team\"\n  - \"reports directly to a founder or executive\"\n  - \"matrixed reporting\"\n  - \"recently through layoffs or restructuring\"\n  - \"distributed team across timezones\"\n\nsuggested_red_line_starters:\n  - \"player-coach with a full IC workload\"\n  - \"no hiring authority for my own team\"\n  - \"team inherited mid-performance-plan\"\n  - \"reorg announced but not completed\"\n\nvibe_prompt: >\n  Name 1-3 teams or organizations whose *way of working* you admire — how they\n  make decisions, handle disagreement, treat people leaving. One line each on\n  WHY. For a leadership role the culture reason is the signal, not the logo.\n\n# Leadership roles are judged more on the org than on the title,\n# and comp bands are wider — weights shift accordingly.\naxis_weights:\n  role_fit: 20\n  domain_fit: 15\n  org_fit: 25\n  vibe_fit: 25\n  comp_fit: 15","readmeExcerpt":"Skill: JD - Triage Owner: bwancoding Summary: Scores a job posting on two independent dimensions — how much you want it (five weighted axes against your own criteria) and how likely you are to get it (your skills vs its stated requirements) — then returns one action. Any market, language, or profession. Tags: latest:1.1.1 Version history: v1.1.1 | 2026-07-27T03:22:23.293Z | user Fixes a language leak: a non-English p","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"<emoji> <TIER>          Desirability: <tier>   Candidacy: <tier>\n\nWant it\n  Role fit     ★★★★☆\n  Domain       ★★★★★\n  Org          ★★★☆☆\n  Vibe         ★★☆☆☆   anchor \"<name>\" — \"<JD phrase>\"\n  Comp         ★★★★☆\n  → weighted <n.n>/5\n\nCan get it\n  Meets <k>/<n> stated must-haves\n  ✅ <met>            ⚠️ <partial — in progress>            ❌ <gap>\n\n<one sentence: the actual judgment>\n\nOpen questions\n- <only real unknowns; omit the section entirely if none>\n\nLogged: JD-YYYYMMDD-NNN"},{"language":"text","snippet":"❌ OUT\nTriggered: <gate or red line, with location and exact phrase>\n<one sentence: why>\n\nMatched anyway\n- <aligned dimensions worth remembering — omit if genuinely none>\n\nLogged: JD-YYYYMMDD-NNN"},{"language":"text","snippet":"🎯 STRETCH APPLY        Desirability: Strong   Candidacy: Stretch\n\nWant it\n  Role fit     ★★★★★\n  Domain       ★★★★★\n  Org          ★★★★☆\n  Vibe         ★★★★☆   anchor \"Basecamp\" — why: \"small team, no growth theater\"\n                       triggered by: \"we ship deliberately\", \"no on-call\"\n  Comp         — (info insufficient)\n  → weighted 4.6/5 across 4 axes\n\nCan get it\n  Meets 2/5 stated must-haves\n  ✅ SQL   ✅ experiment design\n  ⚠️ Kubernetes (learning — half credit)\n  ❌ 5 years managing a team   ❌ regulated-industry experience\n\nStrong on everything you control; the management requirement is the one real\nblocker, and it's the kind they usually probe rather than verify.\n\nOpen questions\n- Is the team-management requirement firm, or would mentoring experience clear it?\n- What's the full package, and is the posted number base or all-in?\n\nLogged: JD-20260725-001"},{"language":"text","snippet":"📊 <N> roles evaluated, <first date> → <last date>\n\nWhere they came from\n  <org trait>: <n>          ← grouped by the user's own org_traits vocabulary\n  <org trait>: <n>\n  unclassified: <n>\n\nTitles that keep appearing\n  <title pattern>: <n>\n\nWhat they ask for\n  <requirement>: <n>/<N> postings — you have it (mastered)\n  <requirement>: <n>/<N> postings — you're learning it       ← highest ROI\n  <requirement>: <n>/<N> postings — gap\n\nRed lines\n  \"<pattern>\": fired <n>× — <k> OUT, <m> CONDITIONAL\n\nYour two dimensions\n  Desirability: <n> Strong · <n> Good · <n> Weak · <n> Poor\n  Candidacy:    <n> Likely · <n> Plausible · <n> Stretch\n  Both high: <n>   ← the roles actually worth your time\n\nOutcomes (of <n> entries with Outcome filled)\n  <action tier>: applied <n>, interviewing <n>, rejected <n>, offer <n>\n\n💡 <2-4 observations, each traceable to a number above>"},{"language":"text","snippet":"🎯 <role name>\n   Based on <n> matching postings in your history\n\nRequirements this role asks for\n   ✅ <requirement>            you have it — <n>/<N> postings asked\n   ⚠️ <requirement>            learning — <n>/<N> asked\n   ❌ <requirement>            gap — <n>/<N> asked\n\nNext, in order\n   1. <item> — asked in <n>/<N> postings, you're already partway\n   2. <item> — asked in <n>/<N>, not started\n   3. <item> — rarer, but blocks the roles you rated highest\n\nEvidence to build\n   <item>: <one concrete artifact that would let you claim it in an interview>"},{"language":"text","snippet":"3. Red line: \"individual revenue target\"\n      From: Posting B, \"own a quarterly booking number\" — you skipped this one.\n      Why (draft): a quota changes what the job optimizes for.\n      Keep / edit / drop?"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: jd-triage\ndescription: \"Career decision system for job seekers. Scores a job description on two independent dimensions — how much you want it (5 weighted axes against your stored criteria) and how likely you are to get it (your skills vs the JD's stated requirements) — then returns one concrete action. Use when (1) the user pastes a job description or recruiter message, (2) the user invokes /jd-triage or asks 'should I apply for this role', (3) the user asks to list, compare, or analyze previously evaluated roles, (4) the user asks what to learn next for a target role, (5) the user asks to set up, update, or reset their career criteria. Market-, language-, and profession-neutral; bootstraps a criteria profile on first run.\"\n---\n\n# jd-triage · v1.1.1\n\nA JD is evaluated on **two independent dimensions**, never collapsed into one number:\n\n- **Desirability** — do you want this? Five weighted axes scored against the user's stored criteria.\n- **Candidacy** — can you get this? The JD's stated must-have requirements vs the user's skills inventory.\n\nA role you want but can't get is a *stretch*, not a *skip*. A role you can get but don't want is a *backup*, not an *apply*. Collapsing both into one star rating destroys that distinction — which is the whole decision.\n\nResponsibilities:\n\n1. **Bootstrap & maintain** a criteria profile at `~/.openclaw/workspace/jd_criteria.md`.\n2. **Evaluate** a JD → two-dimension verdict + one action.\n3. **Log** every evaluation to `~/.openclaw/workspace/jd_history.md`.\n4. **Analyze / Plan** over accumulated history (see `references/analysis-commands.md`).\n\n## Language\n\n**Default to English.** If the user writes in another language, respond entirely in that language for the rest of the session.\n\n| Surface | Language |\n|---|---|\n| All conversational output — bootstrap Q&A, verdicts, tables, **and the verdict tier as displayed** | User's language (English by default) |\n| `jd_criteria.md` field keys, `jd_history.md` structural labels, verdict tier names **in storage** | **Always English** — grep-friendly, stable across language switches |\n| Stored free-text values (org names, summaries, red-line rationales, JD quotes) | The language the user wrote them in, at write time |\n\n**Never auto-translate stored content.** When listing or comparing entries written in different languages, render structural labels in the current language and show stored free text verbatim. Quotes pulled from a JD keep the JD's original language even when the surrounding output is translated — a translated quote is no longer evidence.\n\n## State machine\n\nOn every invocation, read `~/.openclaw/workspace/jd_criteria.md` and branch:\n\n| State | Condition | Action |\n|---|---|---|\n| **S1: Missing** | File does not exist | **Quick Start** (5 questions) → proceed to the requested command |\n| **S2: Schema gap** | File exists, `schema_version` < 3 | Migrate silently where possible, ask only for fields that cannot be inferred (see `references/bootstrap.md § Mig"},{"path":"README.md","content":"# jd-triage\n\n**Two questions, kept apart: do you want it, and can you get it?**\n\nPaste a job posting. Get a verdict against the criteria *you* defined — plus an\nhonest read on whether you'd clear the bar. Most JD filters collapse both into\none score, which is exactly the information you needed.\n\nA skill for [OpenClaw](https://github.com/openclaw). Works in any market, any\nlanguage, any profession.\n\n---\n\n## What it does\n\n- **Scores two independent dimensions.** Desirability from five weighted axes\n  against your stored criteria; Candidacy from the posting's stated must-haves\n  against your skills. A role you want but can't get is a **stretch**, not a\n  skip. A role you can get but don't want is a **backup**, not an apply.\n- **Weights red lines by where they appear.** \"Owns revenue targets\" in the title\n  is an instant no. The same phrase in the last bullet, framed as *support*, is a\n  question to ask the recruiter — not a rejection.\n- **Makes vibe judgments inspectable.** Every vibe rating quotes the posting and\n  names the anchor it reasoned from. Anchors carry your *reason*, so the skill\n  works on a 12-person studio nobody has heard of, not just famous logos.\n- **Turns unknowns into questions.** Missing comp, ambiguous scope, unclear\n  remote policy — each becomes a line you can paste into a reply to the recruiter.\n- **Logs everything, including rejections.** Over time, `analyze` shows which\n  patterns keep reaching you and which requirement you keep almost meeting.\n\n## Starting up\n\nFive questions. Not thirteen.\n\nQuick Start asks for your role family and market, what titles you want, your\nfloors (comp with basis, locations, remote), your automatic no's, and one to\nthree organizations you admire *with a line on why each*. That is enough to\nevaluate. Everything else is asked once, at the moment it first matters.\n\nPrefer showing over telling? `/jd-triage learn` reads a handful of postings you\nliked and a handful you passed on, then proposes your red lines and anchors for\nyou to accept or edit.\n\n## Commands\n\n| Command | What it does |\n|---|---|\n| Paste a posting, or `/jd-triage` | Evaluate |\n| `/jd-triage quickstart` | The 5-question setup |\n| `/jd-triage learn` | Derive criteria from example postings |\n| `/jd-triage update` \\| `reset` | Edit criteria, current values pre-filled |\n| `/jd-triage history [apply\\|out]` | Last 10 evaluations |\n| `/jd-triage compare <id1> [<id2>]` | Side by side |\n| `/jd-triage analyze` | Patterns across everything you've evaluated (needs 8+) |\n| `/jd-triage plan` | Which gap to close next, ranked by what postings actually ask for |\n\nNatural language works too, in your language: \"should I apply to this\",\n\"和上次对比\", \"what should I learn next\".\n\n## Sample output\n\n```\n🎯 STRETCH APPLY        Desirability: Strong   Candidacy: Stretch\n\nWant it\n  Role fit     ★★★★★\n  Domain       ★★★★★\n  Org          ★★★★☆\n  Vibe         ★★★★☆   anchor \"Basecamp\" — why: \"small team, no growth theater\"\n                       triggered by: \"we shi"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7fsvwdsd1ktv3vdfztehe7mx821jdh\",\n  \"slug\": \"jd-triage\",\n  \"version\": \"1.1.1\",\n  \"publishedAt\": 1785122543293\n}"},{"path":"references/analysis-commands.md","content":"# Analyze & Plan\n\nBoth commands read accumulated history. Both refuse to run on too little data —\na trend drawn from four postings is a horoscope.\n\n| Command | Needs | Below that |\n|---|---|---|\n| `/jd-triage analyze` | ≥ 8 entries in `jd_history.md` | Say how many exist and how many more are needed. Do not produce a partial report |\n| `/jd-triage plan` | `skills` and at least one `target_roles` entry | Point at `/jd-triage update`. If history has ≥ 8 entries, use it to rank gaps; otherwise say the ranking is based on the role description alone |\n\n**Report only what is in the data.** Empty category → \"none yet\". Never fill a\nsection by inference.\n\n---\n\n## `/jd-triage analyze`\n\nRead every entry plus the criteria file.\n\n```\n📊 <N> roles evaluated, <first date> → <last date>\n\nWhere they came from\n  <org trait>: <n>          ← grouped by the user's own org_traits vocabulary\n  <org trait>: <n>\n  unclassified: <n>\n\nTitles that keep appearing\n  <title pattern>: <n>\n\nWhat they ask for\n  <requirement>: <n>/<N> postings — you have it (mastered)\n  <requirement>: <n>/<N> postings — you're learning it       ← highest ROI\n  <requirement>: <n>/<N> postings — gap\n\nRed lines\n  \"<pattern>\": fired <n>× — <k> OUT, <m> CONDITIONAL\n\nYour two dimensions\n  Desirability: <n> Strong · <n> Good · <n> Weak · <n> Poor\n  Candidacy:    <n> Likely · <n> Plausible · <n> Stretch\n  Both high: <n>   ← the roles actually worth your time\n\nOutcomes (of <n> entries with Outcome filled)\n  <action tier>: applied <n>, interviewing <n>, rejected <n>, offer <n>\n\n💡 <2-4 observations, each traceable to a number above>\n```\n\n### Rules\n\n- **Group by the user's own vocabulary.** Bucket organizations using their\n  `org_traits`, not a taxonomy of your own. Anything that fits none is\n  `unclassified` — a large unclassified count is itself the finding, and means\n  their trait list is missing something.\n- **Requirement demand** is counted from stored requirement text across entries,\n  cross-referenced with `skills`. Rank by `frequency × (1 − credit)`: something\n  asked for constantly that the user is halfway through learning outranks\n  something rarer they have not started.\n- **Red-line review.** If a red line has fired ≥ 3 times and *never* produced an\n  OUT — only CONDITIONAL — say so and offer to demote it to a negative vibe\n  anchor. It is behaving like a preference, not a gate.\n  If a red line has never fired at all across ≥ 15 entries, mention it once;\n  it may be aimed at postings the user is not even seeing.\n- **Calibration, only with outcomes.** If ≥ 5 entries have an `Outcome`, compare\n  predicted Candidacy against what happened. Report it flatly:\n  *\"Of 6 rated Stretch, 3 got a first interview — the Candidacy read may be\n  running pessimistic.\"* Fewer than 5 → skip the section entirely, do not hedge\n  a guess.\n- **Never infer market conditions.** The sample is the user's inbox, not the job\n  market. Say \"the roles reaching you\", never \"the market is\".\n\n---\n\n## `/jd-triage plan`\n\nPer target"},{"path":"references/bootstrap.md","content":"# Bootstrap\n\nThree ways in. Default to **Quick Start** — a profile that exists is worth more\nthan a perfect profile the user abandoned halfway through.\n\n| Mode | When | Cost |\n|---|---|---|\n| **Quick Start** | S1 (no file), `/jd-triage quickstart` | 5 questions |\n| **Derive from examples** | `/jd-triage learn`, or offered when a profile is thin | Paste a few JDs |\n| **Full** | S5 (`update` / `reset`), or user asks | All fields |\n\nWrite to `~/.openclaw/workspace/jd_criteria.md` using `assets/criteria-template.yaml`.\nField keys English; values in the user's language.\n\n## Using presets\n\n`assets/presets/*.yaml` are **menus, never defaults**. Pick the preset matching\nthe user's `role_family`, show the suggested traits and red-line starters as a\nnumbered list, and write only the lines the user selects — reworded however they\nlike. Never silently write a preset value. `axis_weights` are the one exception:\nthey are a starting distribution, applied unless the user changes them, and\nmentioned once so the user knows they exist.\n\n---\n\n## Quick Start — 5 questions\n\nAsk one at a time. Accept \"skip\" on any of them.\n\n**1. Context.** \"What kind of role, what market, and which languages can you work\nin?\" → `context.role_family`, `context.market`, `context.languages`.\nFrom the market, infer `context.comp_convention` and **state the inference for\nconfirmation** (\"I'll assume comp is quoted as an all-in annual number — correct?\").\n\n**2. Target.** \"What titles are you looking for, and what should the organization\nactually do?\" → `soft_axes.target_title_keywords`, `soft_axes.target_domains`.\n\n**3. Floors.** \"What's the lowest offer you'd accept — and is that base or\nall-in? Where can you work, and is remote acceptable?\" → `hard_gates.comp_floor`\n(amount, currency, period, basis), `hard_gates.locations`, `hard_gates.remote_ok`.\n\n**4. Automatic no's.** \"Anything that makes a role an instant no — and why?\"\n→ `hard_gates.red_lines`. Push for the *why* on each one; it is what makes\nmatching work across languages and rewordings. \"None\" is a valid answer.\n\n**5. Anchors.** Use the preset's `vibe_prompt`. Ask for 1–3 organizations, teams,\nor products the user admires, **each with one line on why**.\n→ `soft_axes.vibe_anchors_positive`.\n\nThen write the file and say plainly what is not yet filled:\n\n> Saved. Org fit and Candidacy will show *info insufficient* until you add org\n> traits and your skills — I'll ask for those the first time they matter.\n\n### Just-in-time capture\n\nDo not front-load the rest. Ask for a field the first time an evaluation\nactually needs it, once, inline:\n\n- **Skills** — before scoring Candidacy for the first time: \"To score whether you\n  can get this, I need your skills. List what you could be interviewed on today,\n  and separately what you're actively learning.\" → `skills.mastered`,\n  `skills.learning`. Write them to the file so this is asked only once.\n- **Org traits** — the first time a JD's org type looks decision-relevant.\n- **Negative anchors** — the"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2135,"uniquenessScore":40,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T11:15:45.112Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T11:15:45.112Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T14:13:06.175Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}