CRITICAL — Before starting, you MUST confirm that the okp CLI is installed and can connect to the API:
npm install -g @markbangwu/okp
okp domains # 确认 API 可达
Permission Model
public: admin/host > writer > reader
private: host > writer > reader
- admin: global administrator, can manage public domains. Has no bypass permissions whatsoever for private domains, must accept a reader/writer invitation before being able to read or write, and still cannot manage private domains.
- host: each domain has exactly one host, automatically granted to the domain creator. Responsible for managing the domain README, members, and invitation codes. The host is non-transferable.
- writer: domain writer. Can be obtained via invitation. Can write concepts, cannot manage members and invitation codes.
- reader: the default read-only permission for public domains; in private domains it must be explicitly obtained via invitation.
Domains are public by default. The creator can choose private; private domains will not appear in domains, search, sample, links, or export for non-members.
Create a new domain → automatically become host
Writing a README creates a domain, and the creator automatically becomes the sole host of that domain:
okp domain <domain> --set readme.md
Returning 201 means creation succeeded, and the creator already holds the host role.
Create a private domain:
okp domain <domain> --set readme.md --visibility private
Obtain writer permission
If put / batch / domain --set returns 403 (write access denied):
- Have the host of that domain (for public domains, an admin may also do so) generate an invitation code:
okp invite create <domain> --expires-hours 72 --max-uses 1 # 多人共用同一码时:--unlimited - The current user accepts:
okp invite accept OKP-XXXX-XXXX - Confirm membership:
okp invite members <domain>
A public domain invitation code grants writer. A private domain can invite reader or writer, and cannot grant host or admin:
okp invite create <private-domain> --role reader
okp invite create <private-domain> --role writer
The invitation code is a short code, not a link route. The "Invite" button in the top-right corner of the portal can also be used to enter the same invitation code.
Workflow (strictly in order)
Step 1: Read the domain README
Each domain has its own README, which defines the frontmatter field specification.Must be read first.
okp domain <domain> # 打印 README(含 schema 定义)
okp domains # 查看所有 domain
okp domains -q <keyword> # 模糊搜索领域名
If it is a new domain, write the README first and then import (writing the README defines the domain, and afterwards okp domains is immediately visible):
okp domain <domain> --set readme.md
README format (YAML frontmatter defines the schema):
---
fields:
sender:
type: string
required: true
description: 飞书发送者用户名
group:
type: string
required: true
description: 来源飞书群
platform:
type: enum
required: false
enum: [bilibili, douyin, xiaohongshu, github, youtube]
date:
type: string
required: false
description: 发布日期 YYYY-MM-DD
---
# feishu-social
飞书社媒分享数据...
## How to contribute
每条 concept 的 frontmatter 必须包含 sender 和 group。
Step 2: Check for duplicates (search-before-insert)
okp search "<title>" --domain <domain> --type <type>
- If results with similar semantics are found → determine whether they are the same concept → if so, update using the existing id; otherwise change the title to distinguish them
Step 3: Distill the concept JSON
Key fields:
{
"id": "feishu-social/Link/太离谱了居然可以在自己画的虚拟世界游玩",
"domain": "feishu-social",
"type": "Link",
"title": "太离谱了!居然可以在自己画的虚拟世界游玩!",
"description": "一句话摘要,不超过 500 字符",
"tags": ["AI视频", "虚拟世界"],
"body": "markdown 正文",
"frontmatter": {
"sender": "寇佳新",
"group": "the World Builders",
"platform": "bilibili",
"date": "2026-07-06",
"url": "https://b23.tv/zyhaEno",
"likes": "225",
"views": "6357"
},
"provenance": {
"source": "feishu-sync",
"agent": "okp-import/1.6",
"raw_ref": "https://..."
}
}
Fill in the frontmatter according to the schema in the domain README. Required fields cannot be omitted, otherwise the write returns 422.
Step 4: Write
# 单个
okp put <id> -f concept.json
# 批量(NDJSON,每行一个 concept)
okp batch concepts.ndjson
put and batch behave the same:
- New write / content has changed → after being persisted, automatically enters the searchable index (asynchronous, usually within seconds)
- Idempotent re-import with unchanged content → skip the write; if this entry had not previously been indexed, the server will make it up
- Do notlook for a separate "build index / embed" command—there isn't one, and it isn't needed
Common failures:
| Status | Meaning | Handling |
|---|---|---|
| 403 | No domain write permission | Contact the host/admin to generate an invitation code, then okp invite accept <code> |
| 422 | frontmatter/validation failed | Press fix to fill in the field or rewrite |
| 401 | token invalid/expired | Check OKP_API_TOKEN / sandbox execution token |
Common items for 422 fix :
frontmatter.<field> 是必填字段→ fill in this field疑似重复→ useokp searchto confirm whether it already existsprovenance.source 为空→ fill in the data source
Step 5: Verify
After the write returns success, wait a moment before searching (for large batch imports, wait a few more seconds):
okp sample --domain <domain> --limit 3 # 随机抽样确认数据结构
okp search "<title 关键词>" --domain <domain> --limit 5
okp search --domain <domain> --sort date:desc --limit 5 # 时序类看最新
okp get <id> # 确认单条完整
If the concept just written cannot be found for the time being: wait a few more seconds and retry okp search / okp get; do not rewrite it unless the content itself needs to be changed.
id naming convention
{domain}/{type}/{slug} # slug 用 kebab-case,避免中文和空格
provenance required fields
| Field | Description |
|---|---|
source |
Data source, e.g. feishu-sync、manual、fandom-crawl |
agent |
Writer, e.g. okp-import/1.6 |
raw_ref |
Original data URL or path |
Invite-related CLI (host/admin)
okp invite create <domain> [--expires-hours 72] [--max-uses 1 | --unlimited]
okp invite list <domain>
okp invite revoke <domain> <invite-id>
okp invite accept <code>
okp invite members <domain>
- On create, the plaintext code is shown only once
- list does not return the plaintext code
--max-usesRange 1-100, default 1;--unlimitedmeans unlimited times (the two are mutually exclusive)- The invite role for a public domain is fixed to
writer - The invite role for a private domain can be
readerorwriter
Delete
# writer/host 可删除有写权限 domain 中的 concept;公开 domain 的 admin 也可删除
okp delete <concept-id> --yes
# private domain 只有 host 可删除;公开 domain 的 host/admin 可删除
okp domain <domain> --delete --yes
Deleting a domain permanently cleans up that domain's concepts, links, revisions, members, and invites.
Out of scope for this skill
- Knowledge search → okp-search
- Portal UI operations beyond domain README maintenance
- Data crawling → each domain's own data pipeline