jobs-market

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

jobs-market

就业市场

Turn a natural-language market question into the right
sjctl market
call(s) and present the result. The public API exposes two distinct market endpoints — this skill's job is picking the right one from how the question is phrased.
将自然语言的市场问题转换为正确的
sjctl market
调用,并呈现结果。公开API提供两个不同的市场端点——本技能的任务是根据问题的表述选择合适的端点。

Running sjctl

运行sjctl

Resolve the
sjctl
binary in this order and use the first that works:
  1. sjctl
    on
    PATH
  2. ~/.solid-jobs-skills/bin/sjctl
    (
    sjctl.exe
    on Windows) — where the installer puts it
  3. ./sjctl
    /
    ./sjctl.exe
    in the current repo (local dev)
  4. If none exist, install it, then use the path the installer prints on stdout:
    • macOS/Linux:
      curl -fsSL https://raw.githubusercontent.com/solid-company/solid-jobs-skills/v0.6.0/scripts/install-sjctl.sh | bash
    • Windows:
      irm https://raw.githubusercontent.com/solid-company/solid-jobs-skills/v0.6.0/scripts/install-sjctl.ps1 | iex
    • Dev fallback (Go installed, inside the repo):
      go run ./cmd/sjctl
Always pass
--json
so you can parse and reason over the results, then summarize for the user. Both endpoints reflect the whole live market — they need no prior search and are independent of the local offer cache used by
stats
.
按以下顺序查找
sjctl
二进制文件,使用第一个可用的:
  1. 系统
    PATH
    中的
    sjctl
  2. ~/.solid-jobs-skills/bin/sjctl
    (Windows系统为
    sjctl.exe
    )——安装程序的默认存放路径
  3. 当前仓库中的
    ./sjctl
    /
    ./sjctl.exe
    (本地开发环境)
  4. 若上述路径均无该文件,则先安装,再使用安装程序在标准输出中打印的路径:
    • macOS/Linux:
      curl -fsSL https://raw.githubusercontent.com/solid-company/solid-jobs-skills/v0.6.0/scripts/install-sjctl.sh | bash
    • Windows:
      irm https://raw.githubusercontent.com/solid-company/solid-jobs-skills/v0.6.0/scripts/install-sjctl.ps1 | iex
    • 开发环境备选(已安装Go,在仓库内):
      go run ./cmd/sjctl
务必传递
--json
参数,以便解析和处理结果,再为用户进行总结。两个端点均反映整个实时市场——无需预先搜索,且独立于
stats
使用的本地职位缓存。

Two endpoints, one decision

两个端点,一次决策

Question shapeCommandWhat you get
Current/typical pay, demand, "right now" for a division, category, subcategory, subcategory group, or city
sjctl market <scopeKind> <scopeKey> --json
A flat live snapshot:
demand
,
salary
(percentile band + B2B/permanent),
experience
,
topLocations
,
topSkills
"Over the years", "trend", "has X changed", "last N years", a single role or skill name (e.g. "Golang", "ManualTester")
sjctl market raport <role> --json
A
years[]
array, oldest→newest, up to 3 calendar years: offer volume, contract-type split, seniority split, B2B/UoP salary bands, top skills — one entry per year, plus a nested
quarters[]
array per year
(Q1→Q4, same breakdown minus top skills) for quarter-level questions
Both in one ask (e.g. "is Go pay rising, and what's typical now?")Call bothPresent the current snapshot and the yearly trend together
Key differences to keep straight:
  • scopeKind matters for the first, not the second.
    market <scopeKind> <scopeKey>
    needs a
    scopeKind
    ∈ {division, mainCategory, subcategory, subcategoryGroup, city}.
    market raport <role>
    takes only a role/skill name as
    scopeKey
    — pass
    raport
    itself as the first argument, never a scopeKind.
  • --fields
    only works on the scope endpoint.
    It filters
    demand,salary,experience,topLocations,topSkills
    . Passing
    --fields
    with
    market raport
    is rejected — the raport response is always returned whole.
  • Denominators are local, not global, in the raport response: each year's (and each quarter's)
    contractType.total
    and
    seniority.total
    are independent of
    offerCount
    and of each other — don't assume any of them sum to the year's/quarter's total offers.
    salaryB2B
    /
    salaryUoP
    can be
    null
    — or the key entirely absent — for a year or quarter with no matching data.
  • The raport is quarterly under the hood. Each
    years[]
    entry carries a
    quarters[]
    array (Q1→Q4, oldest first) with the same fields as the year itself except
    topSkills
    (year-only). The current, still-in-progress year may have fewer than 4 quarters.
问题类型命令返回内容
当前/典型薪资、需求、“当下”的部门、类别、子类别、子类别组或城市相关问题
sjctl market <scopeKind> <scopeKey> --json
实时扁平快照:
demand
salary
(百分位区间 + B2B/全职)、
experience
topLocations
topSkills
“这些年来”、“趋势”、“X是否有变化”、“过去N年”、单个岗位或技能名称(例如“Golang”、“ManualTester”)
sjctl market raport <role> --json
years[]
数组(从旧到新,最多3个日历年):职位数量、合同类型占比、职级占比、B2B/UoP薪资区间、热门技能——每年一条记录,此外每年包含嵌套的
quarters[]
数组
(Q1→Q4,除热门技能外的相同细分数据),用于季度级问题
同时询问两种情况(例如“Go语言的薪资是否在上涨,当前典型薪资是多少?”)调用两个端点同时呈现当前快照和年度趋势
需要明确的关键差异:
  • 第一个端点需指定scopeKind,第二个不需要
    market <scopeKind> <scopeKey>
    需要
    scopeKind
    ∈ {division, mainCategory, subcategory, subcategoryGroup, city}。
    market raport <role>
    仅接受岗位/技能名称作为
    scopeKey
    ——第一个参数必须是
    raport
    ,绝不能是scopeKind。
  • --fields
    仅对范围端点生效
    。它用于过滤
    demand,salary,experience,topLocations,topSkills
    。在
    market raport
    中传递
    --fields
    会被拒绝——报告响应始终返回完整内容。
  • 报告响应中的分母是本地而非全局的:每年(及每季度)的
    contractType.total
    seniority.total
    独立于
    offerCount
    且彼此独立——不要假设它们的总和等于年度/季度的总职位数。
    salaryB2B
    /
    salaryUoP
    可能为
    null
    ——或完全不存在该键——表示对应年份或季度无匹配数据。
  • 报告底层按季度统计。每个
    years[]
    条目包含
    quarters[]
    数组(Q1→Q4,从旧到新),字段与年度数据相同(除
    topSkills
    仅年度有)。当前尚未结束的年份可能不足4个季度。

Examples

示例

sjctl market subcategory React --json                  # current snapshot for a specialization
sjctl market division IT --fields salary,demand --json # narrowed snapshot
sjctl market city warszawa --json                       # a whole city (no topLocations)
sjctl market raport Golang --json                        # 3-year trend for a role
sjctl market raport ManualTester --json
sjctl market subcategory React --json                  # 某细分领域的当前快照
sjctl market division IT --fields salary,demand --json # 精简后的快照
sjctl market city warszawa --json                       # 整个城市的快照(无topLocations)
sjctl market raport Golang --json                        # 某岗位的3年趋势
sjctl market raport ManualTester --json

Presenting results

结果呈现

Snapshot (
market <scopeKind> <scopeKey>
): lead with the salary band (min/p25/median/p75/max) and demand (
activeOffers
,
remotePercentage
), then note the top few
topSkills
/
topLocations
if relevant to the question.
Raport (
market raport <role>
): render a compact year-over-year table — year, offer count, seniority split (junior/regular/senior %), and the B2B regular/senior median band — since that's what "has pay changed" questions need. Only expand into contract-type or top-skills detail per year if asked. Skip years with all-zero
contractType
/
seniority
totals in the narrative (they mean no usable breakdown that year, not zero offers —
offerCount
is the real volume figure) but still show the row.
For a quarter-specific question ("how was Q3", "last quarter", "kwartał"), drill into that year's
quarters[]
array instead of stopping at the yearly row — same fields as the year (minus
topSkills
), one entry per quarter. Don't unpack every quarter of every year by default; only go quarterly when the question asks for that resolution or when a yearly figure looks like it needs the finer trend to explain (e.g. a mid-year swing).
快照
market <scopeKind> <scopeKey>
):优先展示薪资区间(最小值/p25/中位数/p75/最大值)和需求数据(
activeOffers
remotePercentage
),如果与问题相关,再提及几个热门
topSkills
/
topLocations
报告
market raport <role>
):生成紧凑的年度对比表格——年份、职位数量、职级占比(初级/普通/高级 %)以及B2B普通/高级中位数薪资区间,因为这是“薪资是否变化”类问题所需的信息。仅当用户询问时,才展开每年的合同类型或热门技能细节。在叙述中跳过
contractType
/
seniority
总数全为零的年份(这表示该年没有可用的细分数据,而非零职位——
offerCount
才是真实的数量指标),但仍需显示该行。
对于季度特定问题(例如“第三季度情况如何”、“上一季度”、“kwartał”),深入到对应年份的
quarters[]
数组,而非停留在年度数据——季度数据包含与年度相同的字段(除
topSkills
外),每个季度一条记录。默认不要展开每一年的所有季度;仅当问题要求该粒度,或年度数据需要更精细的趋势来解释时(例如年中波动),才使用季度数据。

Notes

注意事项

  • The API rate limit is 300 req/min; don't loop market calls needlessly — one scope call and/or one raport call per question is normally enough.
  • Role names for
    raport
    are free text matched against the API's data (e.g.
    Golang
    ,
    React
    ,
    ManualTester
    ). Two distinct "no data" outcomes, don't conflate them:
    • Unrecognized role name
      sjctl
      exits non-zero with an API error (the endpoint 404s). Tell the user the role name wasn't recognized and suggest a close match (e.g. category/subcategory name from
      jobs-search
      ).
    • Recognized role, no history
      sjctl
      exits 0 with an empty
      years
      array (human output prints "no raport data for this role"). Tell the user there's no yearly data for that role rather than treating it as a search failure.
  • A salary band with
    salaryRangeCount: 0
    means no data for that seniority/contract-type that year — all-zero, not literally "PLN 0". Never report a zero band as a real salary figure.
  • API速率限制为每分钟300次请求;不要不必要地循环调用市场接口——通常每个问题调用一次范围查询和/或一次报告查询就足够。
  • raport
    的岗位名称为自由文本,与API数据匹配(例如
    Golang
    React
    ManualTester
    )。两种不同的“无数据”结果,不要混淆:
    • 未识别的岗位名称——
      sjctl
      以API错误退出(端点返回404)。告知用户该岗位名称未被识别,并建议相近的匹配项(例如来自
      jobs-search
      的类别/子类别名称)。
    • 已识别岗位,但无历史数据——
      sjctl
      以0状态退出,返回空的
      years
      数组(人类可读输出显示“该岗位无报告数据”)。告知用户该岗位没有年度数据,而非将其视为搜索失败。
  • salaryRangeCount: 0
    的薪资区间表示该年份该职级/合同类型无数据——全零,并非字面意义上的“0 PLN”。切勿将零区间报告为真实薪资数字。