Derivon CLI

The Derivon CLI is a stateless JSON processor for non-negative weighted directed B-hypergraphs. It is designed for Agents, scripts, and Unix pipelines.

This English manual is normative. The Chinese manual is a maintained translation; when the two disagree, the English contract takes precedence.

The CLI accepts graph data, not an entire Derivon authoring document. Extract the graph before invoking it:

jq '.graph' workspace.json | derivon validate

Every invocation processes exactly one complete graph. The CLI stores no graph between commands and does not edit input files in place.

Mathematical Scope

A Derivon hyperedge contains zero or more tail points, exactly one head point, and a non-negative weight:

h = (tails, head, weight)

All tails are required before the head can be derived. Multiple hyperedges with the same head are alternative derivations. Empty tails, parallel hyperedges, and cycles are valid.

Derivon is not a general-purpose graph CLI. It does not assign ordinary directed-graph semantics to a multi-tail hyperedge.

Output Contract

Successful commands write JSON to stdout. stdout never contains prompts, progress messages, or logs. Errors are written as structured JSON to stderr.

Mutation commands write the complete transformed graph. Read and query commands write only their result. A failed mutation writes no partial graph. Output is compact by default; --pretty uses two-space indentation. Successful JSON ends with one newline.

--help, command-level --help, and --version are the only plain-text stdout exceptions. They do not read graph input.

Installation

The derivon binary is distributed by the MIT-licensed derivon-cli package and follows Semantic Versioning. The first release is 0.1.0, tagged derivon-cli-v0.1.0.

Cargo

cargo install derivon-cli

Homebrew

brew install derivon-research/tap/derivon

Derivon is a Homebrew formula, not a cask. The separate derivon-research/homebrew-tap repository owns the formula and bottles. Rust is a build dependency, not a runtime dependency.

Installer

curl -fsSL https://docs.derivon.net/cli/install.sh | sh

The noninteractive installer accepts:

DERIVON_VERSION=latest
DERIVON_INSTALL_DIR=$HOME/.local/bin
DERIVON_INSTALL_METHOD=auto

An explicit version is an exact SemVer such as 1.2.3; ranges and prereleases are not selected by latest. Byte-for-byte repeated installation is supported.

On macOS, auto delegates to Homebrew when available and otherwise to Cargo. It does not download an unsigned macOS executable, bypass Gatekeeper, or install either package manager. If neither tool is available, installation stops with instructions.

On Linux, auto downloads a static x86_64-unknown-linux-musl or aarch64-unknown-linux-musl archive; cargo explicitly selects source installation. The installer downloads into a temporary file, verifies SHA-256, runs derivon --version, and atomically replaces an existing installation only after both checks succeed.

The installer never uses sudo, modifies shell startup files, or changes PATH. If the install directory is absent from PATH, it prints instructions. Unsupported systems fail without guessing another target.

Version 0.1 does not distribute standalone macOS or Windows archives. Linux archives are named derivon-VERSION-TARGET.tar.gz and contain the binary, root license, and README. Releases include SHA256SUMS and build provenance.

derivon --version reports the CLI version and default graph schema:

derivon 0.1.0 (default graph schema: derivon.graph/v1)

Unix Pipeline

The default graph input is stdin:

derivon point add B < graph.json > graph-with-b.json

--input selects a file instead:

derivon --input graph.json point get A

When --input is present, the CLI reads that file and does not inspect stdin. Without --input, it reads exactly one graph from stdin. The CLI has no in-place edit mode and does not own an output-file option. Use shell redirection when a result should be stored.

Commands compose through standard pipes because every mutation emits a complete graph. Use --pretty only at the end of a pipeline when formatted output is useful:

derivon point add B < graph.json \
  | derivon hyperedge add h-ab --tail A --head B --weight 1.5 \
  > updated-graph.json

An authoring document contains graph-independent fields which the CLI must not receive. Use an external JSON processor to extract or replace its graph:

jq '.graph' workspace.json | derivon query closure --start A

For several changes that must succeed or fail together, use atomic apply rather than a multi-process pipeline:

derivon apply --operations changes.json < graph.json > updated-graph.json

Graph Format

The CLI directly accepts the graph fragment used by the Derivon mind-map authoring format:

{
  "points": [
    {
      "id": "A",
      "data": { "label": "A" }
    },
    {
      "id": "B",
      "data": { "label": "B" }
    }
  ],
  "hyperedges": [
    {
      "id": "h-ab",
      "weight": 1.5,
      "tails": ["A"],
      "head": "B",
      "data": { "source": "example" }
    }
  ]
}

The optional top-level schema is "schema": "derivon.graph/v1". Input without a schema means exactly derivon.graph/v1, not whichever version is newest. Unknown versions are rejected.

Mutation and subgraph commands preserve schema presence. Unversioned input remains unversioned; versioned input retains the same schema. The CLI never performs an implicit protocol upgrade or downgrade.

Points

A point has a globally unique string id and optional opaque data.

Hyperedges

A hyperedge has:

  • a globally unique string id;
  • a tails array containing unique point IDs;
  • one head point ID;
  • an exact finite non-negative numeric weight in tenths units no greater than 900719925474099.1; and
  • optional opaque data.

Point and hyperedge IDs share one namespace and are case-sensitive machine identifiers. Agents, scripts, and the mind-map backend own their allocation. Human-facing names and labels belong in data, never in the structural ID.

An ID is 1 to 128 ASCII bytes and matches:

^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$

Tail order has no mathematical meaning. The CLI rejects duplicate tails but preserves the supplied order when transforming a graph.

Weights are parsed as exact decimal values without f64 conversion or rounding. The maximum is 900719925474099.1, whose tenths units equal JavaScript's safe-integer maximum 2^53 - 1. Scientific notation is accepted when its mathematical value is valid; negative zero is accepted and emitted as zero.

Opaque Data

data may contain any JSON value. It is never inspected by validation or derivation logic. A command which does not address data preserves its JSON value. JSON numbers in data retain arbitrary precision and are never converted through binary floating point. Duplicate object keys are rejected everywhere, including inside data.

Preservation is semantic rather than textual. Whitespace, object-key order, numeric spelling such as 1.0, and Unicode escape spelling may change after serialization.

Unknown structural fields outside data are rejected. Every command validates the complete input graph before operating. Mutations validate the complete result again. Validation reports deterministic issues but does not repair, sort, or normalize input.

Valid Edge Cases

Empty graphs, isolated points, empty-tail hyperedges, self-dependencies, cycles, parallel hyperedges, zero-weight edges, and zero-weight cycles are valid. A hyperedge may refer to a point appearing later in the points array because array position is not declaration order.

Identity conflicts, duplicate IDs or tails, unknown point references, missing required fields, unknown structural fields or schema, invalid weights, and duplicate JSON keys are invalid.

Ordering

Point and hyperedge arrays retain input order. Add operations append; rename operations modify an item in place. Ordinary query result sets use deterministic ID ordering. Executable derivation order is preserved as computed. Output object keys are ordered deterministically; compact output has no unnecessary whitespace and pretty output uses two spaces.

Resource Limits

Graph input is limited to 256 MiB by default. Operation and value files are limited to 64 MiB. Explicit byte-limit flags may raise these limits. JSON nesting depth is fixed at 128 and cannot be disabled. There is no separate point or hyperedge count limit.

Runtime Contract

Derivon business commands are offline, stateless mathematical operations.

They do not:

  • access the network;
  • send telemetry, check for updates, or report crashes;
  • read user-level configuration;
  • create caches, state directories, or lock files;
  • discover authoring workspaces or .derivon directories; or
  • vary JSON fields, help, or diagnostics with the system locale.

The CLI reads only stdin and files explicitly named by command arguments. The current working directory is used only to resolve relative paths. HOME, locale, and network state do not alter the result for the same explicit input.

Machine fields, help, and diagnostic messages are English. Error messages are not stable for parsing; machine decisions use error codes and paths. The user manual is bilingual, with English as the normative version.

Compatibility

The first CLI release is package version 0.1.0 with Git tag derivon-cli-v0.1.0. Package-prefixed tags avoid collisions with existing workspace tags.

CLI

Before 1.0, patch releases preserve the contract within one minor line. A new 0.x minor may make documented incompatible changes. After 1.0, incompatible command, successful-output, error-code, or apply-operation changes require a new CLI major.

Minor-compatible releases may add commands, optional flags, and error codes, so consumers must handle unknown codes. Patch releases fix defects without changing the mathematical result or JSON shape for previously valid input. Automation should pin a compatible CLI line, such as 0.1.x before 1.0 or a major version after 1.0. Apply arrays follow that CLI compatibility line.

Graph Protocol

derivon.graph/v1 is frozen once released. Any incompatible structure change requires a new graph schema, even while the CLI is below 1.0. Unversioned graph input always means graph/v1; it never means the newest schema.

New CLI lines continue to read older graph schemas unless an incompatible release explicitly deprecates support in advance. The CLI never performs an implicit graph upgrade or downgrade.

Documentation

GitHub Pages publishes main under https://docs.derivon.net/cli/dev/. A tag such as derivon-cli-v0.1.0 publishes the latest 0.1.x manual under /cli/v0.1/; after 1.0, releases publish major paths such as /cli/v1/. /cli/ points to the latest released manual, while the site root currently points to /cli/. English is normative and each version's Chinese translation is under its version path at /zh/.

Commands

Commands are grouped by graph resource and operation:

validate
point list|get|add|remove|rename|data get|data set|data remove
hyperedge list|get|add|remove|rename|set tails|set head|set weight|data get|data set|data remove
query closure|route|diagnose
subgraph route|reachable|induced
apply

Global options are:

--input <FILE>
--pretty
--max-input-bytes <N>
--max-value-bytes <N>
-h, --help
-V, --version

Graph input defaults to stdin. When --input is present, stdin is not inspected. Byte limits are positive decimal values; zero is not an unlimited sentinel. Business options have stable long names only.

Point and hyperedge mutations emit a complete graph. Reads emit bare JSON entities or values without an envelope. validate passes a valid graph through unchanged. Query commands do not mutate input. Successful JSON is compact unless --pretty is present.

--data and --value accept JSON text and are mutually exclusive with --data-file and --value-file. Plain strings therefore require JSON quotes. Pointers are empty or begin with /.

Point Commands

derivon point list
derivon point get <ID>
derivon point add <ID> [--data <JSON> | --data-file <FILE>]
derivon point remove <ID> [--cascade] [--ignore-missing]
derivon point rename <ID> <NEW_ID>
derivon point data get <ID> [POINTER]
derivon point data set <ID> [POINTER] (--value <JSON> | --value-file <FILE>)
derivon point data remove <ID> [POINTER] [--ignore-missing]

Mutations emit the complete transformed graph. New points are appended. If no payload is supplied for a new point, its data defaults to {}; explicit --data null preserves null.

Point rename updates all hyperedge tail and head references atomically while retaining array position. Renaming to an existing point or hyperedge ID, including itself, fails.

Removing a referenced point fails by default. point remove A --cascade removes the point and every hyperedge whose tails or head reference it. All CRUD operations are strict. Unknown IDs and collisions fail. --ignore-missing is available only for remove operations. Removing an unknown point with both --cascade and --ignore-missing is a successful no-op. Cascading an existing unreferenced point succeeds normally.

Data

Data commands use RFC 6901 JSON Pointer. Omitting the pointer addresses the complete data value. Missing intermediate parents fail; set may create its final object member and may append to an array with -. JSON null is a value, not a removal request. Large values may come from --value-file.

Removing the root omits the data field. Removing an array element shifts later elements toward zero; /- is invalid for remove. Missing paths fail unless --ignore-missing is present.

Absent and null data are valid. A complete data set may replace either with any JSON value. A subpath get, set, or remove under absent or null data returns pointer_type_mismatch and never promotes the value or panics. --ignore-missing does not suppress type mismatches. Setting an existing value to an equal JSON value succeeds; removing a missing path with --ignore-missing is a successful no-op.

Hyperedge Commands

derivon hyperedge list
derivon hyperedge get <ID>
derivon hyperedge add <ID> [--tail <POINT_ID>]... --head <POINT_ID> --weight <WEIGHT>
  [--data <JSON> | --data-file <FILE>]
derivon hyperedge remove <ID> [--ignore-missing]
derivon hyperedge rename <ID> <NEW_ID>
derivon hyperedge set tails <ID> [--tail <POINT_ID>]...
derivon hyperedge set head <ID> <POINT_ID>
derivon hyperedge set weight <ID> <WEIGHT>
derivon hyperedge data get <ID> [POINTER]
derivon hyperedge data set <ID> [POINTER] (--value <JSON> | --value-file <FILE>)
derivon hyperedge data remove <ID> [POINTER] [--ignore-missing]

Mutations emit the complete transformed graph. New hyperedges are appended; absent data defaults to {}, while explicit null is preserved. CRUD is strict: unknown IDs and global ID collisions fail, including rename to the same ID. --ignore-missing is available only for remove; removing an unknown edge with it is a successful no-op.

Every referenced point must exist. Duplicate tails are rejected. Empty tails are valid; set tails without --tail sets an empty tail. Parallel hyperedges are valid when their IDs differ.

Weights are exact non-negative decimals no greater than 900719925474099.1 and must be multiples of one tenth. Invalid values are rejected rather than rounded. Scientific notation is accepted by mathematical value and negative zero is emitted as zero.

Data

Data commands follow the same JSON Pointer rules as point data commands. Omitting the pointer addresses the entire payload. Missing intermediate parents fail, a final object member may be created, and - appends to an array.

Root removal omits data. Array removal shifts later elements; /- is invalid for remove. Missing paths fail unless --ignore-missing is present. A subpath operation under absent or null data returns pointer_type_mismatch; the CLI neither promotes the value nor panics, and --ignore-missing does not suppress type mismatches. Same-value set operations succeed. Removing a missing data path with --ignore-missing is a successful no-op.

Query Commands

Query commands inspect a graph without mutating it. Set arguments use repeatable singular flags; duplicate IDs are errors:

derivon query closure --start A --start B
derivon query route --start A --target X --target Y
derivon query diagnose --start A --target X --target Y

Omitting --start selects the empty start set. A route target set must contain at least one point. Set-valued output uses deterministic ID ordering.

Closure returns a self-describing object:

{"startPointIds":["A"],"pointIds":["A","B","X"]}

Route and diagnosis results use reachable as a discriminator. A reachable route contains point and hyperedge IDs, executable order, cost bounds, provenOptimal, and search metrics. An unreachable route contains targetDiagnoses and omits inapplicable solution fields. Diagnosis returns one item for every requested target; reachable targets have empty blockingPointIds and cycles.

Unreachability is a successful query result rather than a malformed-command error. The complete route grammar is:

derivon query route [--start <POINT_ID>]... --target <POINT_ID>
  [--target <POINT_ID>]... [--max-nodes <N>] [--max-millis <N>]

Route search defaults to 200,000 branch nodes and 10,000 milliseconds. Both budgets may be overridden, including with zero to request bounds and an initial witness without branch expansion. There is no unlimited mode or product-level hard maximum.

Atomic Apply

derivon apply --operations <FILE> [--max-operations-bytes <N>]

The operations file cannot be stdin or -. It is an unversioned JSON array whose version follows the CLI compatibility line (0.1.x before 1.0, major version after 1.0). Every item is a typed mutation object.

opRequired fieldsOptional fields and defaults
point.addiddata = {}
point.removeidcascade = false, ignoreMissing = false
point.renameid, newIdnone
point.data.setid, valuepointer = ""
point.data.removeidpointer = "", ignoreMissing = false
hyperedge.addid, head, weighttails = [], data = {}
hyperedge.removeidignoreMissing = false
hyperedge.renameid, newIdnone
hyperedge.set.tailsid, tailsnone
hyperedge.set.headid, headnone
hyperedge.set.weightid, weightnone
hyperedge.data.setid, valuepointer = ""
hyperedge.data.removeidpointer = "", ignoreMissing = false

Explicit data null is preserved. Tails are JSON arrays. Boolean fields require JSON booleans. File-based data/value forms do not exist inside operations. Missing, unknown, or incorrectly typed fields fail the complete apply. Issue paths include the operation array index, for example /operations/3/head.

Operations execute in array order and each intermediate graph must remain valid. Later operations may refer to entities created or renamed earlier. Reads, queries, and subgraph operations are rejected. An empty operation array succeeds and returns the input graph. The same no-op and strictness rules as individual commands apply.

The process mutates one owned graph and needs no rollback copy because no intermediate state is externally visible. The complete result is validated and serialized into memory before stdout is touched. Argument, parse, validation, operation, and serialization failures produce zero stdout bytes.

A final transport failure exits 74 but cannot retract bytes already accepted by the OS. This unavoidable Unix IO case is outside the atomic operation guarantee. Input and operations files remain read-only.

Subgraph Commands

Every subgraph command returns a result envelope:

{
  "graph": { "points": [], "hyperedges": [] },
  "selection": {}
}

Extract .graph explicitly before passing it to another graph command:

derivon subgraph reachable --start A < graph.json \
  | jq '.graph' \
  | derivon validate

Induced

derivon subgraph induced [--point <POINT_ID>]...

No point flags produce the empty graph.

The graph contains exactly the selected points and every hyperedge whose head and all tails belong to that point set. Isolated selected points and eligible empty-tail edges are retained.

Reachable

derivon subgraph reachable [--start <POINT_ID>]...

The command computes closure under the complete input graph, then returns the induced subgraph of that closure. It retains all executable alternatives, not only one route.

Route

derivon subgraph route [--start <POINT_ID>]... --target <POINT_ID>
  [--target <POINT_ID>]... [--max-nodes <N>] [--max-millis <N>]

The graph contains the best-known route hyperedges, every incident point, and requested start or target points not incident to a selected edge. selection is the complete route result, including cost bounds and provenOptimal, so an approximate result is never hidden. If the target set is unreachable, graph is null and selection is the unreachable route result.

All projections preserve schema presence, original array order, IDs, weights, and opaque data. Point-set flags are repeatable and duplicates are errors.

Route Semantics

Given a start set S and target set T, a route is a selected hyperedge set R whose closure from S contains every target in T.

The route cost is:

cost(R) = sum(weight(h)) for h in R

A selected hyperedge is charged once even when several targets or branches reuse it. This is minimum set cost over a B-hypergraph, not an ordinary shortest path.

Minimum set cost is NP-hard. Route search therefore defaults to a 200,000-node and 10,000-millisecond budget. Both values may be overridden, including with zero, but there is no unlimited mode. A completed proof returns provenOptimal: true. If a budget is exhausted, the query still returns the best executable derivation found, a certified lower bound, an upper bound, and provenOptimal: false.

When optimality has not been proven, cost is the best known cost and must not be interpreted as the exact minimum.

A target already present in the start set needs no hyperedge and contributes zero cost. If any requested target is unreachable, the result reports reachable: false rather than treating the graph as malformed.

Determinism

Reachability, exact optimal cost, and certified bounds do not depend on point or hyperedge array order. Equal-cost witnesses are not canonical across equivalent reordered graphs. For identical input and node budget, a witness is deterministic when the wall clock budget does not stop search first.

Set-valued IDs are ASCII-sorted. Executable order is not sorted. Blocking IDs and IDs inside cycles are sorted, then cycles are sorted by their ID sequences. millis is not reproducible. When wall time stops search first, best-known witness and search counters may vary by machine, but every returned bound and witness remains valid.

Errors

stdout is reserved for successful JSON output. Errors are structured JSON on stderr. A failed mutation emits no graph. Messages are diagnostic text and are not a stable machine contract; scripts use code, issue codes, paths, and details.

{
  "error": {
    "code": "invalid_graph",
    "message": "graph validation failed",
    "issues": [
      {
        "code": "unknown_point",
        "path": "/hyperedges/2/tails/0",
        "message": "point `A` does not exist"
      }
    ]
  }
}

Exit And Top-Level Codes

ExitStable top-level codes
0Success, including unreachable queries and exhausted route budgets
64invalid_arguments
65invalid_json, duplicate_key, input_limit_exceeded, nesting_limit_exceeded, unsupported_schema, invalid_graph, invalid_operations, invalid_id, invalid_weight, unknown_point, unknown_hyperedge, id_conflict, point_referenced, invalid_pointer, pointer_not_found, pointer_type_mismatch
66file_not_found, file_unreadable
70internal
74io

Full graph validation uses invalid_graph with issues. Apply structure or operation failure uses invalid_operations; issue paths include operation indexes. A single CLI mutation uses its specific business code. Optional details may carry fields such as id, source, or limit.

Issue Codes

Validation issues use this stable set:

missing_field
unknown_field
invalid_type
invalid_id
duplicate_id
duplicate_tail
unknown_point
invalid_weight
duplicate_key
invalid_pointer
pointer_not_found
pointer_type_mismatch
point_referenced

Parser failures which prevent structural validation return without synthetic follow-up issues. Otherwise issues are ordered by schema/root structure, points in array order, hyperedges in array order, then cross-references. Point fields use id, data order; hyperedge fields use id, weight, tails, head, data. Apply follows operation array and documented field order. Multiple issues at one path sort by issue code.

An invalid parent value suppresses cascading child issues. Unreachability and route budget exhaustion are not errors. A final stdout transport failure exits 74; pipe bytes already accepted by the OS cannot be retracted.

Derivon CLI

Derivon CLI 是面向 Agent、脚本和 Unix 管道的无状态 JSON 处理器,用于非负加权有向 B-超图。

英文手册是规范文本;中文手册是同步维护的翻译。两者冲突时,以英文契约为准。

CLI 只接收 graph,不接收完整的 Derivon authoring 文档:

jq '.graph' workspace.json | derivon validate

每次调用只处理一个完整 graph。CLI 不保存会话状态,也不原地修改输入文件。

数学范围

一条 Derivon 超边包含零个或多个尾点、恰好一个头点和一个非负权重:

h = (tails, head, weight)

所有尾点同时满足后才能推导头点。指向同一头点的多条超边表示备选推导。空尾、平行超边和环都合法。Derivon 不是通用图 CLI。

成功结果只向 stdout 写 JSON;错误以结构化 JSON 写入 stderr。mutation 输出完整 graph,读取和查询命令只输出结果。默认输出紧凑 JSON,--pretty 使用两空格缩进,成功 JSON 以一个换行结束。

--help、命令级 --help--version 是仅有的纯文本 stdout 例外,并且不会读取 graph。

安装

derivon 由 MIT 许可的 derivon-cli package 发布并遵循 Semantic Versioning。首个版本是 0.1.0,tag 为 derivon-cli-v0.1.0

Cargo

cargo install derivon-cli

Homebrew

brew install derivon-research/tap/derivon

Derivon 使用 formula,不使用 cask。独立的 derivon-research/homebrew-tap 仓库维护 formula 和 bottles。Rust 仅是 build dependency。

安装脚本

curl -fsSL https://docs.derivon.net/cli/install.sh | sh

脚本无交互并支持 DERIVON_VERSION=latestDERIVON_INSTALL_DIR=$HOME/.local/binDERIVON_INSTALL_METHOD=auto。显式版本必须是精确 SemVer;latest 不选择 prerelease。

macOS auto 优先 Homebrew,否则 Cargo;不下载未签名 macOS executable、不绕过 Gatekeeper,也不安装包管理器。两者都不存在时停止并说明。

Linux auto 下载静态 x86_64-unknown-linux-muslaarch64-unknown-linux-musl archive,也可显式选择 cargo。脚本下载到临时文件,校验 SHA-256,执行 derivon --version,全部成功后才原子替换旧安装。

脚本不使用 sudo、不修改 shell rc 或 PATH;PATH 缺失时只打印说明。v0.1 不发布独立 macOS/Windows archive。Linux archive 命名为 derivon-VERSION-TARGET.tar.gz,包含 binary、根 LICENSE 和 README;release 提供 SHA256SUMS 与 build provenance。

derivon 0.1.0 (default graph schema: derivon.graph/v1)

Unix 管道

默认从 stdin 读取 graph:

derivon point add B < graph.json > graph-with-b.json

也可以使用 --input

derivon --input graph.json point get A

存在 --input 时,CLI 只读取指定文件且不检查 stdin;没有 --input 时从 stdin 读取一个 graph。CLI 不提供原地编辑或输出文件选项,文件写入由 shell 重定向完成。--pretty 只影响成功 JSON 的格式。

多个 mutation 可以通过管道组合。需要全部成功或全部失败时,使用原子 apply

derivon apply --operations changes.json < graph.json > updated-graph.json

完整 authoring 文档应先由外部工具提取 graph:

jq '.graph' workspace.json | derivon query closure --start A

图格式

CLI 直接接收 Derivon mind-map authoring 格式中的 graph 片段:

{
  "points": [
    { "id": "A", "data": { "label": "A" } },
    { "id": "B", "data": { "label": "B" } }
  ],
  "hyperedges": [
    {
      "id": "h-ab",
      "weight": 1.5,
      "tails": ["A"],
      "head": "B",
      "data": { "source": "example" }
    }
  ]
}

可选的顶层 schema 是 "schema": "derivon.graph/v1"。缺少 schema 时也严格表示 v1,而不是最新版。未知版本会被拒绝。mutation 和 subgraph 保留输入是否携带 schema,不做隐式升级或降级。

点与超边 ID 共用一个区分大小写的命名空间。ID 是由 Agent、脚本和 mind-map 后端管理的机器标识符;展示名称必须放入 data。ID 长度为 1 到 128 个 ASCII 字节,并匹配:

^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$

超边的 tails 不得重复,可以为空;head 必须引用已有点。weight 使用精确十进制,必须为十分之一的整数倍且不超过 900719925474099.1。科学计数法按数学值校验,负零输出为零;CLI 不经过 f64 或舍入。

data 可为任意 JSON 值且不参与验证与推导。data 中的 JSON number 保持任意精度,不经过二进制浮点数。所有位置(包括 data)出现重复对象键都会被拒绝。未修改的 data 保持 JSON 语义等价,但空白、键顺序、数字文本形式和 Unicode 转义形式可能变化。data 外的未知结构字段会被拒绝。

所有命令在执行前完整验证输入 graph;mutation 完成后再次完整验证。validation 确定性报告问题,不修复、排序或规范化输入。

点和超边数组保持输入顺序。add 追加,rename 原位修改,tails 保持传入顺序。普通结果集合按 ID 确定性排序,推导执行顺序不重新排序。输出对象键顺序确定;compact 不含多余空白,pretty 使用两空格。

合法边界

空图、孤立点、空尾超边、自依赖、环、平行超边、零权边和零权环都合法。超边可引用 points 数组中位于其后的点。ID 冲突、重复 ID/tail、未知引用、缺失字段、未知结构字段/schema、非法 weight 和重复 JSON key 都非法。

资源限制

默认 graph 输入上限为 256 MiB,operations/value 文件上限为 64 MiB,可以通过显式字节限制 flag 调高。JSON 嵌套深度固定为 128,不能关闭。不单独限制点或超边数量。

运行时契约

Derivon 业务命令是离线、无状态的数学操作。它们不访问网络,不发送遥测、不检查更新或上报崩溃,不读取用户级配置,不创建缓存、状态目录或 lock file,也不自动发现 authoring workspace 或 .derivon 目录。

CLI 只读取 stdin 和参数显式指定的文件。当前工作目录只用于解析相对路径。相同显式输入的结果不受 HOME、locale 或网络状态影响。

机器字段、help 和诊断 message 使用英文,不随 locale 改变。message 不用于脚本解析,机器判断使用 error code 和 path。用户手册为双语,英文是规范版本。

兼容政策

首个 CLI package 版本是 0.1.0,Git tag 为 derivon-cli-v0.1.0,用 package 前缀避免与 workspace 现有 tag 冲突。

1.0 之前,同一 minor 内的 patch 保持契约兼容;新的 0.x minor 可以通过 release notes 引入不兼容变化。1.0 之后,不兼容的命令、成功输出、error code 或 apply operation 变化需要新的 CLI major。兼容版本可以新增命令、可选 flag 和 error code,消费者必须处理未知 code。自动化应固定兼容版本线,例如 0.1.x

derivon.graph/v1 发布后冻结,即使 CLI 仍低于 1.0,不兼容 graph 结构也必须使用新 schema。缺少 schema 永远表示 graph/v1。CLI 不隐式升级或降级 graph。

GitHub Pages 将 main 发布到 https://docs.derivon.net/cli/dev/derivon-cli-v0.1.0 等 tag 将最新 0.1.x 手册发布到 /cli/v0.1/;1.0 后按 major 发布 /cli/v1//cli/ 指向最新 release,站点根当前指向 /cli/;英文为规范,中文位于各版本的 /zh/

命令

validate
point list|get|add|remove|rename|data get|data set|data remove
hyperedge list|get|add|remove|rename|set tails|set head|set weight|data get|data set|data remove
query closure|route|diagnose
subgraph route|reachable|induced
apply

全局参数为 --input--pretty--max-input-bytes--max-value-bytes--help--version。graph 默认来自 stdin;存在 --input 时不检查 stdin。字节限制必须为大于零的十进制数。业务参数只提供稳定长名称。

mutation 输出完整 graph;读取直接输出实体或 JSON 值;validate 透传合法 graph;query 不修改输入。成功 JSON 默认紧凑,--pretty 使用两空格。

--data/--value 接收 JSON 文本,并分别与 file 形式互斥。普通字符串需要 JSON 引号。pointer 为空或以 / 开头。

点命令

derivon point list
derivon point get <ID>
derivon point add <ID> [--data <JSON> | --data-file <FILE>]
derivon point remove <ID> [--cascade] [--ignore-missing]
derivon point rename <ID> <NEW_ID>
derivon point data get <ID> [POINTER]
derivon point data set <ID> [POINTER] (--value <JSON> | --value-file <FILE>)
derivon point data remove <ID> [POINTER] [--ignore-missing]

mutation 输出完整 graph。新点追加;缺省 data 为 {},显式 null 保留。rename 原子更新全部 tails/head 引用并保持点位置,rename 到自身或已有 ID 会失败。删除被引用点默认失败,--cascade 会删除点和所有引用超边。CRUD 默认严格,--ignore-missing 只用于 remove;未知点带 --cascade --ignore-missing 是成功 no-op。

data 命令使用 RFC 6901 JSON Pointer。省略 pointer 表示整个 data。缺失中间父路径失败;set 可创建最终对象键,数组 - 表示追加。根删除会省略 data,数组删除会使后续元素前移,remove 不接受 /-

缺失和 null data 都合法,整体 set 可替换为任意 JSON。其下的子路径操作返回 pointer_type_mismatch,不会提升类型或 panic;--ignore-missing 不忽略类型错误。set 相同值成功;带 --ignore-missing 删除缺失路径是成功 no-op。

超边命令

derivon hyperedge list
derivon hyperedge get <ID>
derivon hyperedge add <ID> [--tail <POINT_ID>]... --head <POINT_ID> --weight <WEIGHT>
  [--data <JSON> | --data-file <FILE>]
derivon hyperedge remove <ID> [--ignore-missing]
derivon hyperedge rename <ID> <NEW_ID>
derivon hyperedge set tails <ID> [--tail <POINT_ID>]...
derivon hyperedge set head <ID> <POINT_ID>
derivon hyperedge set weight <ID> <WEIGHT>
derivon hyperedge data get <ID> [POINTER]
derivon hyperedge data set <ID> [POINTER] (--value <JSON> | --value-file <FILE>)
derivon hyperedge data remove <ID> [POINTER] [--ignore-missing]

mutation 输出完整 graph。新超边追加;缺省 data 为 {},显式 null 保留。CRUD 严格,rename 到自身失败;--ignore-missing 只用于 remove,并使未知边删除成为成功 no-op。引用点必须存在,tails 不得重复;不传 --tail 表示空尾。ID 不同的平行超边合法。相同值的 set 成功。

weight 使用精确十进制,必须为十分之一的整数倍且不超过 900719925474099.1。不经过 f64 或舍入。科学计数法按数学值校验,负零输出为零。

data 使用与点相同的 JSON Pointer 规则。缺失/null 下的子路径操作返回 pointer_type_mismatch,不会 panic 或提升类型。

查询命令

点集参数使用可重复的单数 flag,重复 ID 是错误:

derivon query closure --start A --start B
derivon query route --start A --target X --target Y
derivon query diagnose --start A --target X --target Y

省略 --start 表示空起始集。route 目标集至少包含一个点。集合结果按 ID 确定性排序。

closure 返回包含 startPointIdspointIds 的对象。route 和 diagnose 以 reachable 作为判别字段:可达 route 包含点、超边、执行顺序、代价上下界、provenOptimal 和搜索指标;不可达 route 包含 targetDiagnoses 并省略不适用的求解字段。diagnose 为每个目标返回一项,可达目标的 blocking 和 cycles 为空。

不可达是成功结果。route 默认预算为 200,000 个分支节点和 10,000 毫秒。两者均可覆盖或设为零以只计算界和初始 witness。CLI 不提供 unlimited 模式或产品级硬上限。

原子 Apply

derivon apply --operations <FILE> [--max-operations-bytes <N>]

operations 不能来自 stdin 或 -。它是跟随 CLI 兼容版本线(1.0 前如 0.1.x,1.0 后按 major)的无 envelope JSON 数组。

op必填字段可选字段与缺省值
point.addiddata = {}
point.removeidcascade = false, ignoreMissing = false
point.renameid, newId
point.data.setid, valuepointer = ""
point.data.removeidpointer = "", ignoreMissing = false
hyperedge.addid, head, weighttails = [], data = {}
hyperedge.removeidignoreMissing = false
hyperedge.renameid, newId
hyperedge.set.tailsid, tails
hyperedge.set.headid, head
hyperedge.set.weightid, weight
hyperedge.data.setid, valuepointer = ""
hyperedge.data.removeidpointer = "", ignoreMissing = false

字段类型严格,未知/缺失字段使整个 apply 失败。operation issue 路径包含数组下标。操作按数组顺序执行且每个中间 graph 都合法,后续操作可引用先前创建或重命名的实体。不允许 read/query/subgraph operation。空数组成功并返回输入 graph,no-op 与严格规则和单独命令一致。

进程只修改自身 graph;全部成功后完整验证并先序列化到内存。业务或序列化失败时 stdout 为零字节。最终 transport 失败退出 74,但不能撤回 OS 已接收的字节。输入文件始终只读。

子图命令

所有 subgraph 命令返回统一 envelope:

{"graph":{"points":[],"hyperedges":[]},"selection":{}}

需要继续管道处理 graph 时显式使用 jq '.graph'

Induced

subgraph induced [--point <POINT_ID>]... 保留指定点,以及 head 和全部 tails 都位于指定点集内的所有超边。孤立选中点和符合条件的空尾超边会保留;没有 point flag 时返回空图。

Reachable

subgraph reachable --start A 先在完整输入 graph 上计算闭包,再返回该闭包点集的 induced subgraph。它保留所有可执行备选超边,而非只保留一条 route。

Route

subgraph route --start A --target X 保留当前最佳 route 的超边、所有相关端点,以及没有连接到选中边的请求 start/target 点。selection 是完整 route result,包含代价界和 provenOptimal,不会隐藏近似结果。不可达时 graph 为 null。

所有投影保留 schema presence、原数组顺序、ID、权重和 opaque data。点集 flag 可重复,重复 ID 是错误。

路径语义

给定起始点集 S 和目标点集 T,路径是一个超边集合 R,使 SR 下的闭包包含 T 中所有目标。

cost(R) = sum(weight(h)) for h in R

一条被多个目标或分支复用的超边只计费一次。这是 B-超图上的最小集合代价,不是普通最短路。

最小集合代价是 NP-hard 问题。搜索默认预算为 200,000 个节点和 10,000 毫秒,允许覆盖或设为零,但没有 unlimited 模式。

完成最优性证明时返回 provenOptimal: true。预算耗尽时仍返回当前最佳可执行推导、认证下界、上界以及 provenOptimal: false。此时 cost 只是当前最佳代价,不得解释为精确最小值。

已经位于起始集中的目标不需要超边,代价为零。任一目标不可达时返回 reachable: false,而不是把 graph 判为格式错误。

确定性

可达性、精确最优代价和认证 bounds 不受 point/hyperedge 数组重排影响,但等价重排 graph 的同代价 witness 不要求 canonical。相同输入和 node budget 且未先触发 wall-time 时 witness 确定。

集合 ID 按 ASCII 排序,executable order 不排序。blocking ID 与 cycle 内 ID 排序后,cycles 再按 ID 序列排序。millis 不可复现;wall-time 先触发时,不同机器的 best-known witness 和计数可以不同,但返回的 bounds 和 witness 始终有效。

错误

stdout 只用于成功 JSON;错误以结构化 JSON 写入 stderr。失败 mutation 不输出 graph。message 仅用于诊断,不是稳定机器契约;脚本使用 code、issue code、path 和 details。

退出码与顶层 Code

退出码稳定顶层 code
0成功,包括不可达和 route 预算耗尽
64invalid_arguments
65invalid_jsonduplicate_keyinput_limit_exceedednesting_limit_exceededunsupported_schemainvalid_graphinvalid_operationsinvalid_idinvalid_weightunknown_pointunknown_hyperedgeid_conflictpoint_referencedinvalid_pointerpointer_not_foundpointer_type_mismatch
66file_not_foundfile_unreadable
70internal
74io

完整 graph validation 使用 invalid_graph 和 issues;apply 结构或 operation 失败使用 invalid_operations;单条 CLI mutation 使用具体业务 code。details 可携带 id、source、limit 等字段。

稳定 issue code 为:missing_fieldunknown_fieldinvalid_typeinvalid_idduplicate_idduplicate_tailunknown_pointinvalid_weightduplicate_keyinvalid_pointerpointer_not_foundpointer_type_mismatchpoint_referenced

无法继续的 parser 错误不制造后续 issue。其余 issue 依次按 schema/顶层、points 数组、hyperedges 数组、cross-reference 排列;实体字段使用文档顺序,apply 使用 operation 数组及字段顺序。同一路径按 issue code 排序。无效父值不产生级联子错误。

不可达和 route 预算耗尽不是错误。最终 stdout transport 失败退出 74,OS 已接收的字节无法撤回。