Query OKR cycles and list/create progress records via feishu-cli. Covers the 3 most frequent OKR operations.
feishu-cli: If not yet installed, go to riba2534/feishu-cli to get the installation method.
Core Concepts
OKR Data Model
Feishu OKR consists of 4 layers of objects, and this skill involves the first 3 layers:
| Layer | Object | Description | This skill's command |
|---|---|---|---|
| 1 | Period | Tenant-level global, such as 2026-Q1. All members see the same period | cycle list |
| 2 | Objective (O) | An objective within a period, belonging to a user | Reference only (--objective-id) |
| 3 | Key Result (KR) | A quantifiable result under an O | Reference only (--key-result-id) |
| 4 | Progress Record | A progress update under an O or KR | progress list/create |
Key Constraints:
- Periods are tenant-level,
cycle listThere is no user_id parameter— everyone sees the same periods. You cannot "query someone's OKR periods", only "query which periods the tenant currently has". - Choose one of Objective ID and Key Result ID(not both): each progress record can only be attached to one objective or one key result.
- Progress records can be independent of a period: the API does not require passing period_id, but usually an O/KR belongs to a period.
Identity: App Token / Tenant Token
The OKR module currently mandates the use of App Token / Tenant Token. Testing shows the OKR server rejects User Token (99991668 user access token not support), so the command does not read --user-access-token, and does not need auth login。
- You need to enable OKR tenant scopes for the app on the Feishu Open Platform
- Locally you only need to configure
FEISHU_APP_ID/FEISHU_APP_SECRETorconfig.yaml - If the server returns
99991672, apply for the corresponding app permission via the Open Platform link in the error
Command Quick Reference
| Subcommand | Description | Required Parameters |
|---|---|---|
okr cycle list |
List all OKR periods of the current tenant | — |
okr progress list |
List all progress under a certain O/KR | --objective-id or --key-result-id |
okr progress create |
Create a new progress entry | Target ID (choose one) + content (choose one) |
cycle list — query tenant OKR periods
# 默认文本输出(带名称 + 时间 + 状态)
feishu-cli okr cycle list
# JSON 输出(脚本消费)
feishu-cli okr cycle list --output json
Output fields:
id— Period ID (used later when creating O/KR, not covered by this skill)zh_name/en_name— Period name (such as "2026-Q1")start_time/end_time— Period start and end timecycle_status— Period status (such as normal / archived)
Implementation Details: Under the hood it makes direct HTTP calls to /open-apis/okr/v1/periods, with automatic pagination.
progress list — query the progress record list
# 查目标下的所有进展
feishu-cli okr progress list --objective-id 7123456789012345678
# 查关键结果下的所有进展
feishu-cli okr progress list --key-result-id 7123456789012345678
# JSON 输出
feishu-cli okr progress list --objective-id 7xxx --output json
Parameters:
| Parameters | Description | Default value |
|---|---|---|
--objective-id |
Objective ID (choose one of the two with --key-result-id choose one of the two) |
— |
--key-result-id |
Key Result ID (choose one of the two with --objective-id choose one of the two) |
— |
--user-id-type |
User ID type:open_id / union_id / user_id |
open_id |
-o, --output |
Output format:json |
Text |
Output fields:
progress_id— progress IDcreate_time/modify_time— created/modified time (converted to local timezoneYYYY-MM-DD HH:MM:SS)progress_rate.percent/progress_rate.status— progress percentage and status (if any)
progress create — create a progress record
Most common: manually sync progress in weekly/daily reports.
Simplest form (plain text)
feishu-cli okr progress create \
--objective-id 7123456789012345678 \
--content "本周完成核心模块联调,下周开始联调测试"
The CLI will automatically wrap plain text into Feishu ContentBlock rich text JSON (paragraph + textRun).
With progress percentage
feishu-cli okr progress create \
--key-result-id 7123456789012345678 \
--content "完成 8/10 任务" \
--progress-percent 80 \
--progress-status normal
--progress-percentnumber (0-100)--progress-statusValues:normal(normal) /risky(at risk) /overdue(overdue) — v1 PR correction: the official Feishu enum does not includedone, what the old docs called done is actually overdue- ⚠️
--progress-statusMust be used together with--progress-percent; passing status alone will cause an error
Rich text (ContentBlock JSON)
For rich text scenarios such as @mentioning someone, embedding links, bolding, etc.:
feishu-cli okr progress create \
--objective-id 7xxx \
--content-json '{"blocks":[{"type":"paragraph","paragraph":{"elements":[{"type":"textRun","textRun":{"text":"加粗内容","style":{"bold":true}}}]}}]}'
--content and --content-json are mutually exclusive, only one can be filled in.
Custom source (source title + URL)
feishu-cli okr progress create \
--objective-id 7xxx \
--content "本周完成 X" \
--source-title "周报:W18" \
--source-url "https://xxx.feishu.cn/docx/abc123"
The progress card will display the source title on the Feishu OKR page, and clicking it jumps to the URL.
Full parameter table
| Parameter | Description | Default value |
|---|---|---|
--objective-id |
Objective ID (choose one of the two with --key-result-id ) |
— |
--key-result-id |
Key Result ID (choose one of the two with --objective-id ) |
— |
--content |
Plain text content (choose one of the two with --content-json ) |
— |
--content-json |
Raw ContentBlock JSON (choose one of the two with --content ) |
— |
--progress-percent |
Progress percentage (number) | — |
--progress-status |
Progress status:normal / risky / overdue |
— |
--source-title |
Source title (flag registration default empty string, client layer injects default value at runtime created by feishu-cli) |
created by feishu-cli |
--source-url |
Source URL (⚠️ required by API; flag registration default empty string, client layer injects default value at runtime https://www.feishu.cn/okr/progress) |
https://www.feishu.cn/okr/progress |
--user-id-type |
User ID type | open_id |
-o, --output |
Output format:json |
Text |
⚠️ Key pitfalls
1. source_url field is mandatory in the API
Feishu OKR progress_record/create API mandates urlunder the source field; if not passed, it will directly error. The CLI already fills in a placeholder value by default https://www.feishu.cn/okr/progress, but it is recommended to explicitly override it with a meaningful URL (such as the weekly report document address), so that the progress card has real jump value on the OKR page.
2. The cycle path is v1/periods not v2/cycles
There has been confusion historically — the correct path for the Feishu OKR period OpenAPI is:
GET /open-apis/okr/v1/periods ✅ 真实存在
GET /open-apis/okr/v2/cycles ❌ 不存在,404
cycle list command's cycle is the CLI subcommand name (more in line with user intuition), the actual call goes through v1/periods. If manually constructing HTTP requests, do not write it incorrectly.
3. progress create goes through the SDK,cycle list / progress list goes through direct HTTP calls
At the implementation level there is a division of labor:
| Command | Implementation method |
|---|---|
progress create |
Feishu Open SDK v3.5.3's Okr.ProgressRecord.Create |
cycle list |
general HTTP client direct call /open-apis/okr/v1/periods |
progress list |
Generic HTTP client direct call (two paths by target type): • OKRTargetObjective: /open-apis/okr/v2/objectives/{id}/progresses• OKRTargetKeyResult: /open-apis/okr/v2/key_results/{id}/progresses |
Reason: In version v3.5.3, the SDK only exposes the Create method for progress records (no List/Get/Update/Delete), so all other capabilities must be assembled manually via HTTP.
4. cycle is tenant-level and has no user_id parameter
Do not attempt to pass --user-id to cycle list— cycles are shared across the entire tenant, and all members see the same list. This point is easily misled by the intuition that "OKR is a personal goal".
Permission requirements (app token / tenant scope)
| Command | Required scope (any one suffices) |
|---|---|
cycle list |
okr:okr:readonly or okr:okr.period:readonly |
progress list |
okr:okr:readonly or okr:okr.progress:readonly |
progress create |
okr:okr or okr:okr.progress:writeonly |
These are app permissions, not OAuth user authorization; enable them through the open platform app permission management page.
Typical workflow
Weekly report progress sync
# 1. 查当前有哪些周期(可选,确认正在哪个 Q)
feishu-cli okr cycle list
# 2. 看某个目标历史进展(可选,回顾上次说了啥)
feishu-cli okr progress list --objective-id 7xxx
# 3. 同步本周进展
feishu-cli okr progress create \
--objective-id 7xxx \
--content "W18: 完成 X 和 Y,下周冲刺 Z" \
--progress-percent 60 \
--progress-status normal \
--source-title "周报 W18" \
--source-url "https://xxx.feishu.cn/docx/<your-weekly-doc-id>"
Scripted batch sync of progress for multiple KRs
for kr_id in 7xxx 7yyy 7zzz; do
feishu-cli okr progress create \
--key-result-id "$kr_id" \
--content "自动同步: 当前推进中" \
--output json
sleep 1
done
Unimplemented capabilities (add CLI later as needed)
The following OKR APIs are all supported by Feishu, but the MVP scope of this PR only covers the 3 most frequent verbs.internal/client layer already partially implemented, CLI subcommands not yet exposed:
| Capability | Status |
|---|---|
okr progress get <progress-id> |
❌ Not implemented |
okr progress update <progress-id> |
❌ Not implemented |
okr progress delete <progress-id> |
❌ Not implemented |
okr progress image upload |
❌ Not implemented (image asset upload) |
okr objective list/get |
❌ Not implemented |
okr key-result list/get |
❌ Not implemented |
okr review list/query(review/retrospective) |
❌ Not implemented |
If needed, when filing an issue or PR, refer to cmd/okr_progress_create.go pattern for extension.
Error handling
| Error | Cause | Solution |
|---|---|---|
必须指定 --objective-id 或 --key-result-id 之一 |
No goal ID passed | Pass one of the two |
--objective-id 和 --key-result-id 只能填一个 |
Both passed at the same time | Keep only one |
必须指定 --content 或 --content-json 之一 |
No content passed | Pass one of the two |
--content 和 --content-json 只能填一个 |
Both passed at the same time | Keep only one |
--progress-status 必须配合 --progress-percent 一起使用 |
Pass status alone | Add --progress-percent |
--content-json 不是合法 JSON |
JSON syntax error | Use jq . to validate before passing |
source_url is required or similar |
Required by Feishu API | The CLI fills in a placeholder by default, so this should not be triggered in theory; if it occurs, pass explicitly --source-url |
99991672 / scope not authorized |
App lacks OKR tenant scope | Go to the open platform app permission management to enable okr:okr* related permissions |
99991668 user access token not support |
Used a User Token | Do not pass a user token; run using app identity |
Related skills
- feishu-cli-auth — General authentication diagnostics; OKR scopes need to be enabled in the open platform app permission management
- feishu-cli-msg — Send Feishu messages (notify leader/group after progress sync)
- feishu-cli-toolkit — Comprehensive toolbox (tasks, calendar, and other weekly report related tools)