@arxo/law

中文文档
0.4.7发布于 2026/10/21Apache-2.0TypeScriptES Module近 30 天下载 2008

Arxo Law — open a canon, ask a closed question, receive the evaluation document with proof. Transport, case assembly and field projection only.

原始使用文档
文档目录16 节
  1. Quickstart
  2. What comes back
  3. How it works
  4. Five questions
  5. Facts
  6. The answer
  7. Run it anywhere
  8. Packages
  9. Canons
  10. API
  11. open(spec, options?)
  12. Case input
  13. Errors
  14. Examples
  15. Performance
  16. Links

A question to the pinned canon de.bgb.fristen@0.1.1 and its answer with proof and hashes

@arxo/law

Ask a pinned canon a closed question. Get the answer, its proof and three hashes anyone can replay. A canon is a law, a standard or a rulebook compiled to a package; the engine runs locally in WebAssembly, offline after install, with byte-identical answers on every machine.

npm node types license

Quickstart · How it works · Questions · Facts · Answer · Run it anywhere · Packages · Canons · API

Quickstart

npm i @arxo/[email protected] @arxo/[email protected]

A 14-day period starts with an event on Saturday 7 March 2026. When does it end? (§§ 187, 188, 193 of the German Civil Code)

import { open } from '@arxo/law';

const bgb = await open('[email protected]', { offline: true });
const end = await bgb.collect('frist_ende', ['frist', '?end'], {
  legalTime: '2026-09-17', timezone: 'Europe/Berlin',
  decisionTime: '2026-09-17T09:00:00Z', knowledgeTime: '2026-09-17T09:00:00Z',
  deadlinePolicy: 'urn:de:corpus:clir:bgb-fristen#BGB_FRISTEN_TAG',
  answers: [{ predicate: 'frist_ereignis', args: ['frist', '2026-03-07'] },
    { predicate: 'frist_dauer_tage', args: ['frist', '14 calendar_day'] },
  ],
});

Output — produced by this exact call and checked on every build. Fourteen days from 7 March land on Saturday 21 March, so § 193 moves the end to the next working day:

end.evaluationStatus    // 'COMPUTED'
end.value[0].value      // '2026-03-23'  (Mon, 23 Mar 2026)
end.proof.nodes.length  // 4: two facts → rule TagesfristEnde → the question
end.hashes.result       // 'sha256:b2faa3a5…'  (with program and semantic)
end.document            // 4423 canonical bytes — replay them anywhere

Terminal: npm i, node frist.mjs, the answer COMPUTED 2026-03-23 with its proof and result hash

Want a ready TypeScript project with this question and a test? npm create arxo@latest my-app.

What comes back

Proof graph: facts frist_ereignis and frist_dauer_tage feed rule TagesfristEnde, which concludes frist_ende(frist, 2026-03-23)

Every answer carries the proof graph the engine built, the norms it relied on with their pinned text, and the canonical evaluation document. The package itself is transport, case assembly and field projection: there is no second evaluator, and a refusal is a value, not an exception.

How it works

Text with provenance, canon, execution, proof, hash

The same mechanics run any canon — a statute, a technical standard, a rulebook or a table of constants. A model can formalize a text; the engine executes it and proves every answer.

Five questions

One ask underneath; pick the shape of the question.

MethodAsksExample
truth(p, args, case)is p(…) established?does the period end on 23 March?
collect(p, args, case)which values? mark the free slot with '?name'when does the period end?
deadline({ date, days, unit }, case)a term under the case's deadline policy14 working days from receipt
calc(term, case)a computed valuean insurance premium
positions(case)duties, prohibitions, powers of the casewho owes what, by when

Two more read the result rather than ask a new question: whyNot(p, args, case) returns the blocker graph of a NEITHER, and unfold(p, { depth }) prints the rules that produce p and their premises, anchored to the pinned text, with no case at all.

Facts

Facts are { predicate, args, state }. Values are bare; the package's declarations type them:

Declared typePass
Date'2026-03-06'
Integer, Natural14 or '14'
Decimal'0.5' — a string, never a JavaScript number
Money'730000 KZT'
Quantity'14 calendar_day'
Booleantrue
an enumthe variant name, e.g. 'Abschlagszahlung'
an entitya short id ('frist') or a full URN

Three states, not two: 'yes' (the default for a listed fact), 'no' (an explicit negative assertion) and 'unknown'. A fact you do not list is unknown; nothing is defaulted.

An unknown relation, a wrong arity, a wrong type or an unknown enum variant throws FactError with the path and the nearest names before the engine runs — which makes the package a safe check layer behind an LLM agent: the model proposes facts, Arxo evaluates and proves.

Qualified names, dependencies and fully spelled arguments

A relation is named by its short name (root package of the world), by package::name as in source ('phys.relativity_core::predicted_ratio'), or by its full StableId. A transitive dependency the link does not list in imports has no package name in the world: name its symbols by StableId. An enum of a dependency is 'de.bgb.fristen::Hoechstfristkategorie::Erbfall', a constant of a dependency 'phys.relativity_core::ComposedSpeedRatio'. A fully spelled argument ({ kind: 'value', type: { name }, value }) passes through unchanged.

The answer

FieldMeaning
evaluationStatusthe discriminant: COMPUTED, MISSING_INPUT, REQUIRES_JUDGMENT, INTERPRETATION_REQUIRED, …
truthStatusa separate axis: TRUE_ONLY, FALSE_ONLY, NEITHER, BOTH
valuethe values of a collect or calc
missingInputswhat a MISSING_INPUT answer lacks
whyNotevery candidate rule, its trigger and each conjunct: SATISFIED, NOT_SATISFIED, UNDETERMINED, CONFLICTED
proofthe proof graph
sourcesthe norms behind the answer, with their pinned text
hashes{ program, semantic, result }
issuesengine messages verbatim — match the codes, not the text
documentthe canonical bytes of the evaluation document
via'local' or 'mcp'; there is no silent fallback between them

"Not in the model" and "the law is silent" are different answers: pkg.passport() repeats the package's formalization measure (EXECUTABLE, SOURCE_ONLY, …) and pkg.inModel(predicate) says whether a name exists at all. pkg.explain(answer) returns the host's text over the same proof.

Exceptions are only for the facade's own failures: FactError, PackageNotFoundError, IntegrityError, TransportError, RpcError.

Run it anywhere

The same methods and the same answer shape on every route.

Node — local engine, offline after install (default)
import { open } from '@arxo/law';
const fristen = await open('[email protected]', { offline: true });

open('name@version') looks for the installed canon, then cacheDir (when given), then the public registry, and checks every canon against its contentHash. The version is required: an answer without a pinned version is not reproducible.

Browser — no node: imports
import { open } from '@arxo/law/browser';   // or the `browser` export condition
import ir from '@arxo/canon-bgb-fristen/package.lawir.json';

const fristen = await open('[email protected]', {
  wasm: fetch('/law_wasm_core.wasm'),
  canons: { '[email protected]': { ir, calendar } },
});

Sources are the canons the bundle carries, the origin's Cache Storage (keyed by contentHash) and the public registry.

Remote host — the Arxo MCP host, no wasm
const picc = await open('[email protected]', { remote: true });

The host answers law_ask; the answer is its projection (evaluationStatus, truthStatus, whyNot, proof, provenance hashes, raw payload in host), and document is null. questions() and passport() need the local CLIR. hostPackage names the catalog key for a remote-only open.

Router — a question in plain words
import { route } from '@arxo/law/router';
const r = await route('Wann endet eine 14-Tage-Frist ab 6. März 2026?', { legalTime: '2026-09-17', answers });

Search → rules → ask on the host. The result is the host's answer or { missing } — the facts the chosen norm needs that you did not give — with the chosen norm and the rejected candidates named.

A case package on disk — saved questions, edits through the law CLI
import { openCasePackage } from '@arxo/law/case-package';

const pkg = await openCasePackage('/path/to/case-package');
const accident = pkg.case('Collision');
accident.questions();                      // saved queries and question cards
const answer = await accident.ask('positions');

await accident.proposeFacts('facts.json', { by: 'urn:example:operator', at: '2026-09-17T12:00:00+05:00' });
await accident.acceptFact('p-0001', { by: 'urn:example:operator', at: '2026-09-17T12:00:00+05:00' });

Reads use the same wasm ask as the CLI; edits run the law binary (the law option, ARXO_LAW_BINARY, the optional peer @arxo/cli, then PATH), so SDK and CLI cannot diverge. A refused edit throws CaseEditError with its LPK-E… code.

law serve — a long-running server you host
const law = await open('[email protected]', {
  serve: { endpoint: 'http://127.0.0.1:8480', token: process.env.LAW_SERVE_TOKEN },
});
const answer = await law.ask('Prosrochka', { kind: 'positions', queryId: 'positions' });
answer.documentBytes;   // the exact embedded evaluation document

law.refreshWorld() picks up a new server generation explicitly. No wasm and no local CLIR on this route.

.arxo containers — a package or saved answers in one file, opened by URL
import { openContainer } from '@arxo/law/arxo';

const box = await openContainer('https://example.org/ogpo-batch.arxo', { wasm: fetch('/law_wasm.wasm') });
await box.inspect();          // descriptor, containerHash, signature — a few KB of the file
await box.replay('001');      // re-evaluates a saved answer: replay.same, replay.document

The engine reads only the byte ranges it needs (HTTP Range), checks CRC, sha256 of every file and, with trustedKeys, the signature. Needs the full module law_wasm.wasm.

Packages

Which Arxo Law package to install: @arxo/law for apps, @arxo/mcp-* for agents, @arxo/cli for the terminal

Canons

InstallOpenAnswers
@arxo/canon-bgb-fristen[email protected]periods and limitation, §§ 186–213 BGB (Germany)
@arxo/canon-ogpo-vts[email protected]compulsory motor liability insurance (Kazakhstan): premiums, limits, payment terms
@arxo/canon-unidroit-picc[email protected]UNIDROIT Principles 2016: application, good faith, interpretation

Each @arxo/canon-* package adds its relation names to the CanonRegistry type, so a misspelled predicate is an editor error. Answer, Fact, CaseInput and the status unions come from @arxo/law-types.

API

open(spec, options?)

spec is 'name@version'. Returns a package with the methods above.

OptionTypeDefault
offlinebooleanfalsenever touch the network; explain refuses
remotebooleanfalseask the Arxo host instead of the local engine
serve{ endpoint, token?, fetch? }—ask your law serve
cacheDirstring—keep downloaded canons on disk, keyed by contentHash
registryUrlstringpublic registrywhere canons are fetched from
mcpEndpointstringArxo hostthe host for remote, explain, route
hostPackagestringfrom the canonthe host's catalog key for a remote-only open
contentHashstring—take exactly these bytes from cacheDir
wasmPathstring | URLbundleda specific engine module
fetchtypeof fetchglobalyour transport

Case input

Field
legalTimethe date the law is read at — required, never defaulted
timezoneIANA zone of the case
deadlinePolicyhow days are counted; without one a term answer is MISSING_POLICY
answersthe facts
decisionTime, knowledgeTimewhen the decision is made, what was known when

Errors

ClassThrown when
FactErrora fact does not fit the package: path, nearest
PackageNotFoundErrorno source has name@version
IntegrityErrorcanon bytes do not match contentHash
TransportError, RpcErrorthe network or the host failed
CaseEditErrorthe law CLI refused an edit: LPK-E… code

Examples

recipes/ holds four 20-line examples, each run in CI: a term end (BGB), a computed value (Kazakh motor insurance), a condition (UNIDROIT) and the check layer behind an LLM agent.

Performance

Wasm cold start 77 ms, one truth question 40 ms, law_wasm_core.wasm 4.7 MB (node bench/measure.mjs, 2026-09-21, darwin 24.6, developer laptop).

arxo.io · Changelog · @arxo/law-engine — the engine without the facade · @arxo/law-types — types · Apache-2.0

版本与发布记录

@arxo/law 共发布 25 个版本,首次发布于 2026/09/21;过去 12 个月发布了 25 个版本。

版本发布日期距今
0.4.7latest2026/10/2117 天前
0.4.62026/10/1622 天前
0.4.52026/10/1622 天前
0.4.42026/10/1424 天前
0.4.32026/10/1425 天前
0.4.22026/10/1326 天前

其他发布通道:next → 0.2.0。

关于 @arxo/law 的常见问题

@arxo/law 是什么?

Arxo Law — open a canon, ask a closed question, receive the evaluation document with proof. Transport, case assembly and field projection only.

如何安装 @arxo/law?

在项目目录运行 npm install @arxo/law,或使用 pnpm add / yarn add / bun add。

@arxo/law 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@arxo/law 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@arxo/law 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@arxo/law 可以商用吗?

@arxo/law 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@arxo/law 的下载量有多少?

根据 npm 官方下载统计,@arxo/law 在 2026/10/07 – 2026/11/05 这 30 天内被下载 2,008 次,日均约 67 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@arxo/law 还在维护吗?

最新版本 0.4.7 发布于 2026/10/21(17 天前);至今共发布 25 个版本,其中过去 12 个月发布了 25 个;首次发布于 2026/09/21。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。