docs← Back to article

Markdown for LLMs

Compatibility

The source Markdown for this article. Copy it into your assistant or download it as a text file.

Download this articlePlain text ↗
# Compatibility

Four matrices: which released versions work together, which operations
each facade ships, where each facade runs, and what touches the
network. Every matrix names its sources, so a version bump becomes a
list of fields and declarations to re-check.

## Version matrix

All four packages below are published versions; the SDK versions match
the repository manifests, and the canon version matches the canon
manifest inside each package.

| SDK | Canon package | Canon (model) |
|---|---|---|
| `@arxo/law` 0.3.3 (TypeScript) | `@arxo/canon-bgb-fristen` 0.1.5 | `de.bgb.fristen` 0.1.0 |
| `arxo` 0.2.0 (Python) | `arxo-canon-bgb-fristen` 0.1.1 | `de.bgb.fristen` 0.1.0 |

```text
@arxo/law 0.3.3                  facade manifest: name and version fields
@arxo/canon-bgb-fristen 0.1.5    canon manifest: name and version fields
arxo 0.2.0                       pyproject: version field; needs-python >= 3.12
arxo-canon-bgb-fristen 0.1.1     pyproject: version field
de.bgb.fristen 0.1.0             canon package-meta: name and version fields
```

The canon manifest pins the linked world by hash (`contentHash` over
`world.lawir.json`, the package hash over `package.lawir.json`), and
the lock file pins the `de.bgb.core` dependency, the calendar
resource, and the resolution hash. The loading chapter shows both
documents. One limit: the two facades do not produce byte-identical
documents for the same question — replay with the facade that
recorded the answer.

## Capability matrix

"Yes" means the operation exists in the shipped API quoted on the
facade pages; "no" means it is absent, with the workaround beside it.

| Operation | TypeScript | Python |
|---|---|---|
| `open(spec, options)` | Yes | Yes, dict options |
| `truth` | Yes | Yes |
| `focused_truth` | `focusedTruth` | No — ask `truth` |
| `why_not` | `whyNot` | `why_not` / `whyNot` |
| `collect` | Yes, `?name` or `{args, free}` | Yes, `?name` or `{args, free, comprehension}` |
| `deadline` (`calendar_op`) | Yes | Yes |
| `calc` (`term`) | Yes | Yes |
| `positions` | Yes | Yes |
| `unfold` | Yes, sync, no case needed | No — read at author time |
| `questions` manifest | Yes | No — read at author time |
| `passport` / `inModel` | Yes | Yes, `in_model` / `inModel` |
| `explain` | Yes, needs the host | Yes, needs the host |
| `verbalize` | Yes, needs engine and pack | No |
| `ask` (uniform request) | Yes, 7 kinds | Yes, 6 kinds (no `focused_truth`) |
| `parseSpec` | Yes | Yes, `parse_spec` |

```text
TS LawPackage surface    canonical declarations: class LawPackage block
TS AskRequest kinds      canonical declarations: AskRequest type
Python LawPackage        package module: LawPackage methods ask/truth/why_not/collect/deadline/calc/positions
Python ask kinds         package module: ask dispatch (truth/why_not/collect/calendar_op/term/positions)
```

## Environment matrix

| Facade | Runs on | Engine | Notes |
|---|---|---|---|
| TypeScript, Node | Node 20 minimum, 24 LTS recommended | Packaged `law_wasm_core.wasm` | Full surface; checkout trees, cache, registry |
| TypeScript, browser | Modern browsers | `wasm` bytes passed in | No Node-only imports; canons from the bundle, pins for Cache Storage |
| TypeScript, serve mode | Any with `fetch` | None local — the server | `open` with `serve` returns `ServePackage` |
| Python | Any OS with Python 3.12+ | Bundled `law_wasm_core.wasm` via `wasmtime` | No registry, remote, or router in this release |

```text
Node floor          facade manifest engines field; quickstart asks for Node 20+
Browser entry       browser declarations: BrowserOpenOptions with wasm/canons/pins
Python floor        pyproject requires-python >= 3.12
Python engine       engine module: bundled wasm path via wasmtime
Serve mode          facade declarations: ServePackage and connectServe
```

## Network matrix

After install, the default path is offline: installed canons answer
from local bytes checked against their manifest hashes.

| Path | Network? | Notes |
|---|---|---|
| TS `open`, installed canon | No | Bytes checked against `contentHash`, then parsed |
| TS `open`, checkout tree | No | `local` root/map/packages |
| TS `open`, disk cache | No | Keyed by content hash |
| TS `open`, registry | Yes | Skipped with `offline: true` |
| TS `explain` | Yes | Host `law_explain` over the carried document |
| TS `verbalize` | No | Local; needs the full engine and a pack |
| TS serve mode | Yes | Every question goes to the server |
| TS router | Yes | Routes over HTTP |
| Python `open` | No | Installed canon, checkout tree, or cache only |
| Python `explain` | Yes | MCP client on first use; offline refuses |
| Python queries | No | Local engine always |

```text
TS sources        open module: installed/tree/cache sources offline, registry unless offline
TS canon check    canon source module: digest-then-parse against package-meta contentHash
TS explain        LawPackage: host law_explain over the carried document
Python sources    open module: canon/tree/cache; registry fetch not in this release
Python explain    package module: host client on first use; offline raises TransportError
```

## Probe record

The examples on these pages are one probed scenario, run on the
versions above: event on 6 March 2026, a duration of 14 calendar days,
candidate end 20 March 2026, legal time 17 September 2026, time zone
Europe/Berlin, counting policy `BGB_FRISTEN_TAG`.

```text
collect frist_ende(frist, ?end)                    COMPUTED  2026-03-20
truth frist_ende(frist, 2026-03-20)                COMPUTED  TRUE_ONLY
truth frist_ende(frist, <wrong date>)              COMPUTED  NEITHER
truth frist_ende(frist, 2026-03-20), partial case  COMPUTED  NEITHER
why_not over the partial case                      2 blockers, one per candidate rule
sources on every answer above                      []
hashes on every answer above                       program, semantic, result
```

The partial case removes the duration fact; the two blockers name the
premises each candidate rule was waiting for. Re-run this probe after
any version move: the verdicts must match, and the program hash names
the new build.

## How to read a cell

Each matrix row ends in a pointer: a manifest field, a declaration
block, or a module. When a version moves, open the pointer first and
update the cell from what it says. For the
worked case behind these pages, see the
[quickstart](/guide/quickstart/) and the
[deadline app](/build/start/).

## Verification record

The example, the pins, the commands, and their observed results for
the versions above:

```text
example   deadline-app 0.1.0 (29 files, sha256 in the Start chapter)
pins      @arxo/law 0.3.3, @arxo/canon-bgb-fristen 0.1.5,
          arxo 0.2.0, arxo-canon-bgb-fristen 0.1.1,
          model de.bgb.fristen@0.1.0, adapter 1.0.0
checked   2026-10-03, Node v20.20.2 and v24.21.0 (63/63 + typecheck
          clean on both; v24 reporter prints `ℹ` summaries), Python 3.13
```

```text
$ cd docs/build/examples/deadline-app && npm test
# tests 63, # pass 63, # fail 0
$ npm run typecheck            # tsc --noEmit, clean
$ python3 python/test_deadline.py
10/10 passed
$ node docs/build/tools/check-fences.mjs
fences checked: 53, verbatim: 39, allowlisted: 14, failures: 0
```

The site build enforces the documentation half of this record:
`content:strict` runs the prose and link gates, and
`deadline-app:archive:check` fails the build when the published
zip, sidecar, or release manifest drifts from the example sources.
Before publishing, one more check compares the pages with a fresh run:

```text
$ node docs/build/tools/check-release.mjs
release: 10 passed, 0 failed
```

It re-runs the suite and asserts the archive, the manifest, the
Start checksum and file count, every quoted test count, the
fences, and the typecheck. Published bytes are immutable
under their name: changed sources ship as a new package version
with a new archive name, never as a silent rewrite. The strict
HTTP run (`npm run test:http:strict` in the unpacked archive,
where sockets listen) belongs to the same pre-publish pass.
Re-run the probe above and these commands after any version move;
if a verdict changes, the matrices on this page change with it.