kanonak-protocol

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Kanonak Protocol

Kanonak协议

Kanonak is an open protocol for defining, versioning, and sharing semantic ontologies across independent publishers. There is no central registry — each publisher serves its own packages from its own domain over plain HTTPS.
Start here, then follow the pointers in "Learn the rules" below. The protocol documents itself: the conventions you need are published as Kanonak packages you can fetch and read, so they stay current as the protocol evolves.
Kanonak是一个开放协议,用于在独立发布者之间定义、版本化和共享语义本体。它没有中央注册表——每个发布者通过普通HTTPS从自己的域名提供包服务。
从这里开始,然后遵循下方「了解规则」中的指引。该协议可自我文档化:你所需的约定以Kanonak包的形式发布,可获取并阅读,因此随着协议演进,这些约定会保持最新。

The one idea to understand first

首先要理解的核心概念

Every class, property, and instance has a stable URI:
publisher/package@version/name
kanonak.org/core-rdf@1.1.0/Class
Two different URLs come off that URI, and it matters that you keep them apart.
每个类、属性和实例都有一个稳定的URI:
publisher/package@version/name
kanonak.org/core-rdf@1.1.0/Class
该URI对应两个不同的URL,你需要区分它们。

The canonical resource URL

规范资源URL

Pure structural substitution — swap
@
for
/
, prefix
https://
:
https://kanonak.org/core-rdf/1.1.0/Class
This mapping is bijective and never requires asking the publisher anything, in either direction. It is also the page a browser renders. Five forms address every target, and publishers may not invent others:
/                              publisher
/{package}                     package, any version
/{package}/{version}           package, pinned
/{package}/{name}              resource, any version
/{package}/{version}/{name}    resource, pinned
纯结构化替换——将
@
替换为
/
,前缀添加
https://
https://kanonak.org/core-rdf/1.1.0/Class
这种映射是双向的,且无需向发布者询问任何信息。它也是浏览器渲染的页面地址。共有五种格式可定位所有目标,发布者不得自行创建其他格式:
/                              发布者
/{package}                     包(任意版本)
/{package}/{version}           包(固定版本)
/{package}/{name}              资源(任意版本)
/{package}/{version}/{name}    资源(固定版本)

The package source URL

包源URL

Where the raw YAML bytes live. That is a separate question, and the answer is publisher-configurable. The default:
https://{publisher}/{package}/{version}.kan.yml
https://kanonak.org/core-rdf/1.1.0.kan.yml
But a publisher can advertise a different layout in
.well-known/kanonak.json
:
json
{
  "version": 1,
  "package_url_template": "https://cdn.example.com/{publisher}/{package}-{version}.yaml"
}
When
package_url_template
is present it wins. The contract is that filling
{publisher}
,
{package}
, and
{version}
yields an
https://
URL whose body is the package source. Beyond that, host, path shape, separators, and file extension are all free — which is what lets a publisher delegate hosting to a CDN. When the config is absent, or omits the field, the default template applies.
A template MUST use all three placeholders —
{publisher}
,
{package}
, and
{version}
. Do not hardcode any of them, even when a value looks fixed for your own site. A template that carries all three resolves for any publisher, which is what lets the same shape serve a shared archive, a multi-tenant host, or the protocol's own default:
https://{publisher}/{package}/{version}.kan.yml
So: derive canonical resource URLs freely, but never hardcode a source URL for a publisher you do not control. Let the CLI resolve it — it reads the publisher's config for you. A package is one YAML file per version, and resolution is just HTTP, so anyone who can serve a file can publish an ontology.
原始YAML字节文件的存储位置。这是一个独立的问题,答案由发布者配置。默认格式如下:
https://{publisher}/{package}/{version}.kan.yml
https://kanonak.org/core-rdf/1.1.0.kan.yml
但发布者可在
.well-known/kanonak.json
中声明不同的布局:
json
{
  "version": 1,
  "package_url_template": "https://cdn.example.com/{publisher}/{package}-{version}.yaml"
}
package_url_template
存在时,它将覆盖默认模板。约定是填充
{publisher}
{package}
{version}
后生成一个
https://
URL,其响应体即为包源文件。除此之外,主机、路径结构、分隔符和文件扩展名均可自由定义——这使得发布者可将托管委托给CDN。当配置文件不存在或省略该字段时,将使用默认模板。
模板必须使用所有三个占位符——
{publisher}
{package}
{version}
。不得硬编码其中任何一个,即使某个值对你自己的站点看似固定。包含所有三个占位符的模板可适用于任何发布者,这使得同一格式可用于共享存档、多租户主机或协议自身的默认模板:
https://{publisher}/{package}/{version}.kan.yml
因此:可自由推导规范资源URL,但切勿硬编码你无法控制的发布者的源URL。 让CLI来解析——它会为你读取发布者的配置。每个版本的包对应一个YAML文件,解析仅需HTTP请求,因此任何能提供文件服务的人都可以发布本体。

Separate the schema from the data

将模式与数据分离

Before writing anything, decide which of two things you are authoring:
  • Schema — the model. What a
    Car
    is: classes and the properties they carry. Changes rarely.
  • Data — instances. The actual cars. Changes constantly.
These belong in separate packages, because they have different lifecycles. Bundled together, every routine data update forces a new version of the schema, which is noisy and breaks the pinning your consumers rely on. Split, each versions at its own pace and many data packages can share one schema.
(If you know the description-logic terms, this is TBox vs. ABox. The protocol just calls it schema and data.)
The session below builds both, in that order.
在编写任何内容之前,先确定你要创作的是以下两者之一:
  • 模式——模型。定义
    Car
    是什么:类及其包含的属性。很少变更。
  • 数据——实例。实际的汽车。频繁变更。
它们应放在不同的包中,因为它们有不同的生命周期。如果捆绑在一起,每次常规的数据更新都需要发布模式的新版本,这会产生大量噪音,并破坏你的消费者依赖的版本固定机制。分离后,两者可各自独立版本化,多个数据包可共享一个模式。
(如果你了解描述逻辑术语,这就是TBox与ABox的区别。本协议仅称之为模式和数据。)
下面的示例将按此顺序构建两者。

What building one looks like

构建流程示例

A worked session. The shape to aim for is: establish purpose, agree the schema, validate, then add data.

AI — What kind of ontology would you like to build?
User — An ontology about cars.
AI — Two questions first, because the answers change the shape of the model:
  1. What will you do with it — catalogue production models, track individual vehicles, compare specifications?
  2. Is there a fixed set of anything (fuel types, body styles), or is everything open-ended?
User — Catalogue production models. Fuel type is a fixed list: petrol, diesel, electric.
AI — Then
FuelType
is an enumeration and belongs in the schema, while the cars themselves are data. Starting with the schema package — classes and properties only, no actual cars in it:
yaml
cars:
  type: Package
  publisher: example.com
  version: 1.0.0
  label: Cars
  comment: The schema — what a car and a manufacturer are.
  imports:
    - publisher: kanonak.org
      packages:
        - package: core-rdf
          match: ^
          version: 1.0.0
          alias: rdfs
        - package: core-owl
          match: ^
          version: 2.0.0
          alias: owl
        - package: core-xsd
          match: ^
          version: 1.0.0
          alias: xsd

Manufacturer:
  type: rdfs.Class
  label: Manufacturer
  comment: A company that builds cars.

Car:
  type: rdfs.Class
  label: Car
  comment: A production car model.

FuelType:
  type: rdfs.Class
  owl.oneOf: [ petrol, diesel, electric ]
  label: Fuel Type
  comment: The fixed set of fuel types a car runs on.

petrol:
  type: FuelType
  label: Petrol

diesel:
  type: FuelType
  label: Diesel

electric:
  type: FuelType
  label: Electric

manufacturerName:
  type: owl.DatatypeProperty
  domain: Manufacturer
  range: xsd.string
  label: Name

modelName:
  type: owl.DatatypeProperty
  domain: Car
  range: xsd.string
  label: Model Name

builtBy:
  type: owl.ObjectProperty
  domain: Car
  range: Manufacturer
  label: Built By

fuel:
  type: owl.ObjectProperty
  domain: Car
  range: FuelType
  label: Fuel
$ kanonak validate cars/1.0.0.kan.yml
1 file(s) validated. 0 error(s), 0 warning(s), 0 info(s).
FuelType
carries
owl.oneOf
, so its three members are part of the model.
Car
carries no such marker, so actual cars are data and belong elsewhere.
User — Add the Golf GTI and the ID. Buzz, both Volkswagen.
AI — Those are data, so they go in their own package that imports the schema:
yaml
cars-inventory:
  type: Package
  publisher: example.com
  version: 1.0.0
  label: Cars Inventory
  comment: The data — actual car models.
  imports:
    - publisher: example.com
      packages:
        - package: cars
          match: ^
          version: 1.0.0
          alias: c

volkswagen:
  type: c.Manufacturer
  c.manufacturerName: Volkswagen

golf-gti:
  type: c.Car
  c.modelName: Golf GTI
  c.builtBy: volkswagen
  c.fuel: c.petrol

id-buzz:
  type: c.Car
  c.modelName: ID. Buzz
  c.builtBy: volkswagen
  c.fuel: c.electric
$ kanonak validate .
2 file(s) validated. 0 error(s), 0 warning(s), 0 info(s).
The inventory can now grow — new models, new manufacturers — without the schema leaving 1.0.0.

Follow that order: purpose → schema → validate → data → validate. Ask what the ontology is for before choosing classes. The answer is what decides which things are enumerations and which are data, and that decision is far cheaper to make now than to unpick after the schema is published.
一个实操流程。目标流程是:确定用途、达成模式共识、验证、然后添加数据。

AI — 你想要构建哪种类型的本体?
用户 — 关于汽车的本体。
AI — 先问两个问题,因为答案会影响模型的结构:
  1. 你将用它做什么——分类量产车型、跟踪单个车辆、对比规格?
  2. 是否存在固定集合(如燃料类型、车身样式),还是所有内容都是开放式的?
用户 — 分类量产车型。燃料类型是固定列表:汽油、柴油、电动。
AI — 那么
FuelType
是一个枚举类型,属于模式,而汽车本身是数据。从模式包开始——仅包含类和属性,不包含实际汽车:
yaml
cars:
  type: Package
  publisher: example.com
  version: 1.0.0
  label: Cars
  comment: The schema — what a car and a manufacturer are.
  imports:
    - publisher: kanonak.org
      packages:
        - package: core-rdf
          match: ^
          version: 1.0.0
          alias: rdfs
        - package: core-owl
          match: ^
          version: 2.0.0
          alias: owl
        - package: core-xsd
          match: ^
          version: 1.0.0
          alias: xsd

Manufacturer:
  type: rdfs.Class
  label: Manufacturer
  comment: A company that builds cars.

Car:
  type: rdfs.Class
  label: Car
  comment: A production car model.

FuelType:
  type: rdfs.Class
  owl.oneOf: [ petrol, diesel, electric ]
  label: Fuel Type
  comment: The fixed set of fuel types a car runs on.

petrol:
  type: FuelType
  label: Petrol

diesel:
  type: FuelType
  label: Diesel

electric:
  type: FuelType
  label: Electric

manufacturerName:
  type: owl.DatatypeProperty
  domain: Manufacturer
  range: xsd.string
  label: Name

modelName:
  type: owl.DatatypeProperty
  domain: Car
  range: xsd.string
  label: Model Name

builtBy:
  type: owl.ObjectProperty
  domain: Car
  range: Manufacturer
  label: Built By

fuel:
  type: owl.ObjectProperty
  domain: Car
  range: FuelType
  label: Fuel
$ kanonak validate cars/1.0.0.kan.yml
1 file(s) validated. 0 error(s), 0 warning(s), 0 info(s).
FuelType
包含
owl.oneOf
,因此它的三个成员属于模型的一部分。
Car
没有此类标记,因此实际汽车是数据,应放在其他位置。
用户 — 添加高尔夫GTI和ID. Buzz,均为大众品牌。
AI — 这些是数据,因此它们应放在单独的包中,并导入模式:
yaml
cars-inventory:
  type: Package
  publisher: example.com
  version: 1.0.0
  label: Cars Inventory
  comment: The data — actual car models.
  imports:
    - publisher: example.com
      packages:
        - package: cars
          match: ^
          version: 1.0.0
          alias: c

volkswagen:
  type: c.Manufacturer
  c.manufacturerName: Volkswagen

golf-gti:
  type: c.Car
  c.modelName: Golf GTI
  c.builtBy: volkswagen
  c.fuel: c.petrol

id-buzz:
  type: c.Car
  c.modelName: ID. Buzz
  c.builtBy: volkswagen
  c.fuel: c.electric
$ kanonak validate .
2 file(s) validated. 0 error(s), 0 warning(s), 0 info(s).
现在库存可以扩展——添加新车型、新制造商——而无需更改模式的1.0.0版本。

遵循此顺序:用途 → 模式 → 验证 → 数据 → 验证。在选择类之前,先明确本体的用途。答案将决定哪些内容是枚举类型,哪些是数据,这个决定在此时做出比模式发布后再修改要容易得多。

Reading those two files

解读这两个文件

  • The first key is the package header. Its name matches the directory. It declares
    publisher
    ,
    version
    , and
    imports
    .
  • Every other top-level key is a resource. What it is comes from its
    type
    .
  • Imports get a document-local
    alias
    .
    rdfs
    is just that file's nickname for
    kanonak.org/core-rdf
    ;
    c
    is the inventory's nickname for the schema. Another document may pick different names for the same packages. Aliases are never global — always resolve them through the file's own
    imports
    block.
  • match: ^
    is the semver operator: accept any compatible version at or above
    1.0.0
    .
    ~
    is minor-compatible,
    =
    is exact,
    *
    is any.
  • Unprefixed names are local; prefixed names cross a package boundary. In the schema,
    range: Manufacturer
    means the
    Manufacturer
    in that same file. In the inventory,
    type: c.Car
    reaches into the imported schema.
  • The parser merges the two into one logical graph at load time, so anything loading both sees
    Car
    and its instances as a single connected model.
  • 第一个关键是包头。它的名称与目录匹配,声明了
    publisher
    version
    imports
  • 其他所有顶级键都是资源。它的类型由
    type
    字段定义。
  • 导入的包会获得文档本地的
    alias
    rdfs
    只是该文件对
    kanonak.org/core-rdf
    的昵称;
    c
    是库存包对模式包的昵称。另一个文档可能为相同的包选择不同的名称。别名永远不是全局的——始终通过文件自身的
    imports
    块解析它们。
  • **
    match: ^
    **是语义化版本运算符:接受1.0.0及以上的任何兼容版本。
    ~
    表示次要版本兼容,
    =
    表示精确匹配,
    *
    表示任意版本。
  • 无前缀的名称是本地的;带前缀的名称跨包边界。在模式包中,
    range: Manufacturer
    指的是同一文件中的
    Manufacturer
    。在库存包中,
    type: c.Car
    指向导入的模式包。
  • 解析器在加载时将两个文件合并为一个逻辑图,因此任何加载这两个文件的工具都会将
    Car
    及其实例视为一个连通的模型。

Why FuelType sits in the schema

为什么FuelType属于模式

FuelType
is a class with named individuals, living in the schema — and that is correct. A closed, fixed set of members (fuel types, statuses, categories, units) is part of the model, not data.
The protocol never guesses which is which. An individual is schema only when explicitly marked:
owl.oneOf
on the class for a closed set of named members, or
sh.in
on a property for a closed set of literal values. A class that merely happens to have instances is not an enumeration — its instances are data.
So
petrol
is schema because
FuelType
declares
owl.oneOf
.
golf-gti
is data because
Car
does not.
Small vocabularies may legitimately mix a few canonical instances into the schema package. At any real scale, keep them apart.
FuelType
是一个包含命名个体的类,属于模式——这是正确的。一个封闭的固定成员集合(如燃料类型、状态、类别、单位)是模型的一部分,而非数据。
协议永远不会猜测哪些属于模式、哪些属于数据。只有当个体被明确标记时才属于模式:类上的
owl.oneOf
用于封闭的命名成员集合,或属性上的
sh.in
用于封闭的字面量值集合。仅包含实例的类不是枚举类型——其实例属于数据。
因此
petrol
属于模式,因为
FuelType
声明了
owl.oneOf
golf-gti
属于数据,因为
Car
没有该声明。
小型词汇表可合理地将一些规范实例混入模式包中。但在任何实际规模的场景中,都应将它们分开。

Get the CLI

获取CLI

bash
npm install -g @kanonak-protocol/cli
kanonak --help
kanonak --help
is authoritative for the command surface. If anything below disagrees with it, believe
--help
.
bash
npm install -g @kanonak-protocol/cli
kanonak --help
kanonak --help
是命令接口的权威参考。如果下方内容与它不一致,请以
--help
为准。

The authoring loop

创作流程

Write, validate, read the error, fix, repeat:
bash
kanonak validate cars/1.0.0.kan.yml
kanonak validate .
Validate the whole workspace with
.
when packages reference each other — that resolves siblings locally, so the data package finds its schema before either one is published.
Validation is not a YAML syntax check. It resolves every import and every reference, fetching published packages over HTTP from their publisher domains. A name that does not resolve is an error, with the fix spelled out:
example.com/cars-inventory@1.0.0:
  ERROR: Reference to 'hydrogen' in 'fuel' could not be resolved
    -> The entity 'example.com/cars/hydrogen' is not defined in this
       namespace or any imported namespace.
  • Import the package that defines it, or check for a typo in 'hydrogen'
  • If it lives in an imported namespace, alias-qualify the reference

2 file(s) validated. 1 error(s), 0 warning(s), 0 info(s).
Read those errors literally — they name the exact URI that failed to resolve. Do not work around one by guessing a name or leaving a value as a plain string.
To see what a published document actually resolved to:
bash
kanonak deps cars/1.0.0.kan.yml
example.com/cars@1.0.0
  kanonak.org/core-rdf@1.1.0
  kanonak.org/core-owl@2.2.0
    kanonak.org/core-xsd@1.1.0
  kanonak.org/core-xsd@1.1.0
Note the resolved versions differ from the
^
floors written in the file. That is the operator doing its job.
编写、验证、读取错误、修复,重复此循环:
bash
kanonak validate cars/1.0.0.kan.yml
kanonak validate .
当包之间相互引用时,使用
.
验证整个工作区——这会在本地解析关联包,因此数据包在发布前即可找到其对应的模式。
验证并非YAML语法检查。它会解析所有导入和引用,通过HTTP从发布者域名获取已发布的包。无法解析的名称会被视为错误,并给出明确的修复建议:
example.com/cars-inventory@1.0.0:
  ERROR: Reference to 'hydrogen' in 'fuel' could not be resolved
    -> The entity 'example.com/cars/hydrogen' is not defined in this
       namespace or any imported namespace.
  • Import the package that defines it, or check for a typo in 'hydrogen'
  • If it lives in an imported namespace, alias-qualify the reference

2 file(s) validated. 1 error(s), 0 warning(s), 0 info(s).
请按字面意思理解这些错误——它们会指出无法解析的准确URI。不要通过猜测名称或将值留为普通字符串来规避错误。
要查看已发布文档实际解析后的依赖关系:
bash
kanonak deps cars/1.0.0.kan.yml
example.com/cars@1.0.0
  kanonak.org/core-rdf@1.1.0
  kanonak.org/core-owl@2.2.0
    kanonak.org/core-xsd@1.1.0
  kanonak.org/core-xsd@1.1.0
请注意,解析后的版本与文件中写入的
^
最低版本不同。这是运算符在发挥作用。

In VS Code

在VS Code中使用

If the person you are working with uses VS Code, suggest the Kanonak Protocol extension (
kanonak-protocol.kanonak
). It runs the same validation live — unresolved references, import cycles, ambiguous types — into the Problems panel as they type, and adds go-to-definition, hover, and completion over
.kan.yml
plus a sidebar browser for exploring publishers and packages. It ships the SDK build and tracks the same version line as the CLI.
如果你的协作伙伴使用VS Code,建议安装Kanonak Protocol扩展(
kanonak-protocol.kanonak
)。它会实时运行相同的验证——将未解析的引用、导入循环、模糊类型等问题显示在「问题」面板中,并为
.kan.yml
文件添加跳转定义、悬停提示和自动补全功能,还提供侧边栏浏览器用于浏览发布者和包。它附带SDK构建,并与CLI保持相同的版本线。

Learn the rules

了解规则

The protocol's conventions are themselves published packages. Install one and read it:
bash
kanonak install kanonak.org/ontology-conventions
It lands in
~/.kanonak/packages/kanonak.org/
. Without the CLI, read the rendered page — a canonical resource URL, so it is always derivable:
Or fetch the source directly. kanonak.org serves at the default template, so this works — but confirm
.well-known/kanonak.json
first for any publisher whose layout you have not checked:
bash
curl https://kanonak.org/ontology-conventions/1.1.0.kan.yml
Each guide is a
Protocol
resource with a
hasConvention
block. Every convention carries required and recommended rules, each with a
rationale
, plus worked valid and invalid examples. When the validator cites a rule by name, find that rule in the installed file and read it directly.
kanonak.org/ontology-conventions
— how to model. Read this before designing anything. Covers: classes vs. properties vs. individuals; datatype vs. object properties;
subClassOf
and multiple inheritance; when an individual belongs to the schema as an enumeration versus being data; constraining properties with shapes.
kanonak.org/kanonak-protocol
— the foundational spec every document obeys regardless of vocabulary. Covers URI structure and canonical URL form, fragments and query strings, publisher/package/resource naming, versioning and file naming, import operators and version resolution, the type system, embedding, references, hierarchy, and the canonical structural hash.
Available versions for any package are listed at its canonical package URL —
https://kanonak.org/ontology-conventions
for this one.
协议的约定本身以包的形式发布。安装一个并阅读:
bash
kanonak install kanonak.org/ontology-conventions
它会安装到
~/.kanonak/packages/kanonak.org/
目录下。如果没有CLI,可阅读渲染后的页面——这是一个规范资源URL,因此始终可以推导得出:
或直接获取源文件。kanonak.org使用默认模板提供服务,因此以下命令有效——但对于任何你未检查过布局的发布者,请先确认
.well-known/kanonak.json
bash
curl https://kanonak.org/ontology-conventions/1.1.0.kan.yml
每个指南都是一个
Protocol
资源,包含
hasConvention
块。每个约定都包含必填和推荐规则,每条规则都有
rationale
(理由),以及有效的和无效的实操示例。当验证器引用某个规则名称时,在已安装的文件中找到该规则并直接阅读。
kanonak.org/ontology-conventions
——如何进行建模。在设计任何内容之前先阅读本指南。涵盖:类vs属性vs个体;数据类型属性vs对象属性;
subClassOf
和多重继承;个体何时作为枚举属于模式而非数据;使用形状约束属性。
kanonak.org/kanonak-protocol
——所有文档无论词汇如何都必须遵循的基础规范。涵盖URI结构和规范URL格式、片段和查询字符串、发布者/包/资源命名、版本控制和文件命名、导入运算符和版本解析、类型系统、嵌入、引用、层次结构以及规范结构哈希。
任何包的可用版本都列在其规范包URL中——例如本指南的URL是
https://kanonak.org/ontology-conventions

Styling with look

使用look系统设置样式

Kanonak packages render as web pages. The look system is the declarative layer that controls how — you style the ontology by adding look declarations to the graph, not by writing a renderer.
Start with the conventions guide, which is also the decision guide for when a look is the right tool versus a transformation or a view:
bash
kanonak install kanonak.org/look-conventions
It covers: choosing an approach; styling types rather than instances; the resource view; path carrier bands; visual identity; display lenses; and the cascade and its universal floor.
The vocabulary itself is
kanonak.org/look
.
Kanonak包可渲染为网页。look系统是控制渲染方式的声明层——你通过向图中添加look声明来为本体设置样式,而非编写渲染器。
从约定指南开始,它也是判断何时使用look工具而非转换或视图的决策指南:
bash
kanonak install kanonak.org/look-conventions
它涵盖:选择方法;为类型而非实例设置样式;资源视图;路径载体带;视觉标识;显示透镜;以及级联和通用基础规则。
词汇本身是
kanonak.org/look

Seeing it

查看效果

Styling is not something to do blind.
kanonak serve
renders your workspace live — the same rendering
kanonak publish
produces — so you can watch a package in a browser as you style it:
bash
kanonak serve --watch
Then open http://localhost:8080.
--watch
reloads on
.kan.yml
changes, so the loop is edit, save, refresh.
There are two modes, and the URL shape differs between them:
  • Open world (the default) — serves any publisher, so the publisher is part of the path:
    /{publisher}/{package}/{version}/{resource}
    , for example
    /example.com/cars/1.0.0/Car
    .
  • Closed world (
    --publisher example.com
    ) — serves that one publisher at the canonical five-form URLs, mirroring what the published site looks like:
    /cars/1.0.0/Car
    .
If a resource 404s in the default mode, a missing publisher segment is usually why.
To write a single rendered artifact to disk instead of serving, use
kanonak derive <resource-uri>
.
设置样式不应盲目进行。
kanonak serve
可实时渲染你的工作区——与
kanonak publish
生成的渲染效果相同——因此你可以在浏览器中查看包的样式变化:
bash
kanonak serve --watch
然后打开http://localhost:8080
--watch
会在
.kan.yml
文件更改时重新加载,因此流程是编辑、保存、刷新。
有两种模式,URL格式有所不同:
  • 开放世界(默认)——提供所有发布者的服务,因此发布者是路径的一部分:
    /{publisher}/{package}/{version}/{resource}
    ,例如
    /example.com/cars/1.0.0/Car
  • 封闭世界
    --publisher example.com
    )——仅提供指定发布者的服务,使用规范的五种格式URL,与已发布站点的外观一致:
    /cars/1.0.0/Car
如果默认模式下资源返回404,通常是因为缺少发布者段。
要将单个渲染产物写入磁盘而非提供服务,请使用
kanonak derive <resource-uri>

Finding things, and getting help

查找内容与获取帮助

kanonak search -q
searches your workspace semantically — by meaning, not literal keyword — which is the quickest way to check whether something is already modelled before you add it again:
bash
kanonak search -q "fuel"
  0.708  Fuel  (ObjectProperty)
         example.com/cars/fuel
  0.681  Petrol  (FuelType)
         example.com/cars/petrol
  0.467  Fuel Type  (Class)
         example.com/cars/FuelType
By default it indexes only your workspace's own resources. Add
--all
to index imported packages too,
--scope kanonak.org/look@
to narrow to a namespace, or
--type <publisher/package/Name>
to list instances of a class. Prefer this over grepping
.kan.yml
files — it searches the resolved graph, not raw text.
The first
-q
run lazily downloads a small embedding model from Hugging Face —
Xenova/all-MiniLM-L6-v2
, 8-bit quantized, about 23 MB — into
~/.kanonak/models
, and reuses it thereafter. Embeddings are cached by content hash, so re-running over an unchanged workspace does not re-embed. Inference is local; that one-time download is the only network access, and your queries never leave the machine. The runtime (
@huggingface/transformers
) is an optional dependency, so if it is missing the command fails with an install hint rather than quietly falling back to something worse.
kanonak ask
runs a local model through Ollama to answer questions about your packages, and it can drive the CLI on your behalf. Reads run freely; anything that changes state stops for a y/N first:
bash
kanonak ask "which packages define a class about fuel?"
It needs Ollama reachable at
http://localhost:11434
and a model that supports tool calls —
--model <tag>
picks one,
--host <url>
points somewhere else.
kanonak search -q
可对你的工作区进行语义搜索——按含义而非字面关键词搜索——这是在添加新内容前检查是否已存在相关建模的最快方式:
bash
kanonak search -q "fuel"
  0.708  Fuel  (ObjectProperty)
         example.com/cars/fuel
  0.681  Petrol  (FuelType)
         example.com/cars/petrol
  0.467  Fuel Type  (Class)
         example.com/cars/FuelType
默认情况下,它仅索引工作区自身的资源。添加
--all
可同时索引导入的包,
--scope kanonak.org/look@
可缩小到指定命名空间,或
--type <publisher/package/Name>
可列出某个类的实例。建议使用此命令而非搜索
.kan.yml
文件——它搜索的是解析后的图,而非原始文本。
首次运行
-q
时会从Hugging Face懒加载一个小型嵌入模型——
Xenova/all-MiniLM-L6-v2
,8位量化,约23 MB——存储到
~/.kanonak/models
目录,并在后续重复使用。嵌入结果按内容哈希缓存,因此对未更改的工作区重新运行不会重新生成嵌入。推理在本地进行;仅首次下载需要网络访问,你的查询永远不会离开本地机器。运行时依赖(
@huggingface/transformers
)是可选的,因此如果缺失,命令会失败并给出安装提示,而非静默降级为其他方式。
kanonak ask
通过Ollama运行本地模型来回答关于你的包的问题,还可代表你调用CLI。读取操作可直接执行;任何会更改状态的操作都会先暂停并等待y/N确认:
bash
kanonak ask "which packages define a class about fuel?"
它需要Ollama可通过
http://localhost:11434
访问,且模型支持工具调用——
--model <tag>
可选择模型,
--host <url>
可指定其他地址。

Things that trip people up

常见误区

  • Do not add instances to a schema package because it is convenient. That couples the model's version to the data's churn, which is the coupling the split exists to prevent.
  • Aliases are document-local. Never assume
    rdfs
    means the same package in two files, and never derive meaning from a name's prefix. Resolve through the file's
    imports
    .
  • Identity is the full URI, not the bare name. Two packages can each define
    Manufacturer
    ; they are different things.
  • Published versions are immutable. Fix a mistake by publishing a new version, never by editing one that is already out.
  • An unresolved reference is an error, not an absence. If something does not resolve, that is a bug to surface — do not work around it by guessing or by falling back to a string.
  • Do not assume where a publisher's source files live.
    <package>/<version>.kan.yml
    is the default, not a guarantee —
    .well-known/kanonak.json
    can point source bytes anywhere. Canonical resource URLs are always structural; source URLs are not.
  • Check the
    .kan.yml
    before assuming a package's shape.
    Fetching it is one HTTP request and settles the question.
  • 不要为了方便而将实例添加到模式包中。这会将模型的版本与数据的变更耦合在一起,而分离模式和数据正是为了避免这种耦合。
  • 别名是文档本地的。永远不要假设两个文件中的
    rdfs
    指的是同一个包,也不要从名称的前缀推导含义。通过文件的
    imports
    块解析别名。
  • 标识是完整的URI,而非裸名称。两个包可以各自定义
    Manufacturer
    ;它们是不同的实体。
  • 已发布的版本是不可变的。修复错误需发布新版本,切勿编辑已发布的版本。
  • 未解析的引用是错误,而非缺失。如果某个内容无法解析,这是一个需要解决的bug——不要通过猜测或回退为字符串来规避。
  • 不要假设发布者的源文件位置
    <package>/<version>.kan.yml
    是默认格式,而非保证——
    .well-known/kanonak.json
    可将源文件指向任何位置。规范资源URL始终是结构化的;URL则不是。
  • 在假设包的结构之前先检查
    .kan.yml
    文件
    。获取它仅需一次HTTP请求即可明确问题。