Start: install, run, and test
This chapter runs the example application; the following chapters take it apart layer by layer. You start from an empty directory and finish with the form open in your browser and the first two answers on screen.
At a glance
Section titled “At a glance”-
Goal: get the example application running from an empty directory and see the first computed answers — the end date of a 14-day period, and the check of a candidate end date.
-
You need: Node.js 20 or newer with npm, plus
curlandunzip; no repository checkout. Versions are listed in the route overview. -
Run:
Terminal curl -O https://docs.arxo.io/build/deadline-app-0.1.0.zipcurl -O https://docs.arxo.io/build/deadline-app-0.1.0.zip.sha256shasum -a 256 -c deadline-app-0.1.0.zip.sha256unzip -q deadline-app-0.1.0.zipcd deadline-appnpm cinpm testnpm start -
Files: this chapter changes nothing; it runs what the archive contains.
Output (none — this chapter only runs what the archive contains)deadline-app-0.1.0.zip 29 files: package.json, package-lock.json, tsconfig.json,README.md, src/*.ts (13), test/*.test.ts (8),test/fixtures (1), python/*.py (2), public/index.html
Check your Node version
Section titled “Check your Node version”The starter needs Node 20 or newer (engines: >=20); for a new setup use
a supported LTS, with Node 24 recommended. Any unzipper works in place of unzip:
the archive is a plain zip. Python 3.12 or newer is needed only for the
Python mirror. The section Choose a Node version
below gives the support dates.
Download and verify the archive
Section titled “Download and verify the archive”Download and verify the versioned archive (example 0.1.0):
curl -O https://docs.arxo.io/build/deadline-app-0.1.0.zipcurl -O https://docs.arxo.io/build/deadline-app-0.1.0.zip.sha256shasum -a 256 -c deadline-app-0.1.0.zip.sha256Expected: deadline-app-0.1.0.zip: OK. (On Linux the same check is
sha256sum -c.) The verified checksum is:
4b8186fcb2caedf9316ff02fdca7032c6713bddc1fe672713fb44eebe0950411Install the pinned dependencies
Section titled “Install the pinned dependencies”Unpack and install the pinned dependencies from the lockfile:
unzip -q deadline-app-0.1.0.zipcd deadline-appnpm cinpm ci installs exactly what package-lock.json pins: @arxo/law
0.3.3 with @arxo/canon-bgb-fristen 0.1.5, plus the pinned
tsx/typescript/@types/node toolchain. No version floats.
Run the tests
Section titled “Run the tests”Run the suite — a separate step, before any server:
npm test# tests 63# pass 63# fail 063 tests pin every answer shape the later chapters rely on:
2026-03-20 for the example case, TRUE_ONLY on the right
candidate, NEITHER on a wrong candidate and on partial facts,
the draft questions from explain, and the capture/replay matrix.
If any line fails here, stop: every later chapter assumes this suite
holds. The last chapter lists each symptom with its cause and fix.
Start the server and see the first answers
Section titled “Start the server and see the first answers”Start the server — it runs in the foreground, so this is its own terminal step:
npm startdeadline-app listening on http://localhost:8787/Open http://localhost:8787/: the form, pre-filled with the example
case. The command line runs the same two calls without the browser:
node --import tsx src/cli.ts evaluate --event 2026-03-06 --days 14node --import tsx src/cli.ts evaluate --event 2026-03-06 --days 14 --candidate 2026-03-20The first call computes the end date. It prints the app’s reading of the answer — headline, rules, hashes; the full SDK shape arrives in chapter 3:
The period ends on 2026-03-20Computed from the event date and the duration by the pinned canon.rules: TagesfristEndesources: No sources anchored in this canon build — the rule names above carry the provenance.program: sha256:468e3fe17c6a28371c6ce8258ae7928c496593673d4b73a52c2a9c40cb50ee33semantic: sha256:90e53b453107dfee9422a5fe24774823430b5c82c3577b9321a0838a6e54c695result: sha256:ae9a7b19361154c868eb9b28d5ac6395b1d2844053259a1abfd6f75e300de812The second call checks the proposed date and establishes it:
Yes — the proposed date is establishedThe engine established that the period ends on the proposed date.rules: TagesfristEndeTRUE_ONLY behind that headline means the computation supports the
claim and not its negation. A wrong candidate answers NEITHER,
which is a normal inconclusive result, not an error — chapter 3
explains why it is not FALSE_ONLY.
How the two answers are produced
Section titled “How the two answers are produced”The model spec names the exact canon version the application pins. It lives in one place, beside the deadline policy and the time zone:
export const MODEL_SPEC = 'de.bgb.fristen@0.1.0';export const POLICY = 'urn:de:corpus:clir:bgb-fristen#BGB_FRISTEN_TAG';export const TIMEZONE = 'Europe/Berlin';The application opens the model once and asks two questions.
buildCollect asks “which dates end this period”; buildTruth asks
“does the period end on this date”. Both read the same facts. Opening
with offline: true resolves the pinned canon locally:
// Calculate mode: which date(s) end the period?export async function evaluateCollect(input: FormInput): Promise<Answer> { const model = await openModel(); const query = buildCollect(); return model.collect(query.predicate, query.args, toCaseInput(input));}
// Verify mode: does the period end on the proposed date?export async function evaluateTruth(input: FormInput, candidate: string): Promise<Answer> { const model = await openModel(); const query = buildTruth(candidate); return model.truth(query.predicate, query.args, toCaseInput(input));}Choose a Node version
Section titled “Choose a Node version”Two versions matter. The minimum the starter supports is Node 20
(engines: >=20), but for a new setup use a supported LTS — Node 24
(“Krypton”, Active LTS until 20 October 2026, supported until 30 April
2028) is the recommended route; Node 20 itself is EOL since April 2026.
Match the release manifest
Section titled “Match the release manifest”The same checksum, file list, and version are bound together in
the release manifest beside the archive,
deadline-app-0.1.0.release.json. If any copy of these numbers —
on a page, in a text export, in a cached view — disagrees with
the manifest, that copy is a stale edition, not a second release:
published bytes never change under their name.
Change the host or port
Section titled “Change the host or port”The server binds loopback only and defaults to port 8787; HOST and
PORT override both:
// Loopback only by default: the printed URL is the reachable URL. // Set HOST=0.0.0.0 deliberately to expose the example on the network. const host = process.env.HOST ?? '127.0.0.1'; const port = Number(process.env.PORT ?? '8787'); createServer().listen(port, host, () => { console.log(`deadline-app listening on http://${host === '127.0.0.1' ? 'localhost' : host}:${port}/`); });Limits and errors
Section titled “Limits and errors”- A checksum mismatch on the download means a corrupt or substituted file: re-download, do not proceed.
PackageNotFoundonopenModelmeans the canon package is not installed. The fix isnpm ci, not a looser version.- Node below 20 is outside
engines(>=20), but that field alone only warns: withoutengine-strictnpm installs anyway, and the starter ships no.npmrcto harden it. If old-Node symptoms appear, the fix is upgrading Node — not a looser version. The troubleshooting chapter lists each symptom with its fix.
Check your understanding
Section titled “Check your understanding”The suite you ran above (npm test, 63 of 63 passing) is this chapter’s
test run; there is no need to repeat it. Run one call the chapter has
not shown yet — the check of a wrong candidate:
node --import tsx src/cli.ts evaluate --event 2026-03-06 --days 14 --candidate 2026-03-21Not established either wayThe engine neither established nor refuted the proposed date; it does not guess.rules: TagesfristEndeBefore reading each answer, predict it.
The CLI prints an end date for one command and a yes-or-no headline for the other. What decides which question it asks?
The --candidate flag. Without it the CLI calls evaluateCollect,
which asks for the end date (buildCollect). With it the CLI calls
evaluateTruth, which checks that one date (buildTruth).
What happens if you run the first command without the --days flag?
The CLI refuses it before any engine call. It prints
error: durationDays must be an integer from 1 to 36500 and exits with
code 2; no answer is computed and nothing is guessed in place of the
missing duration.
The lockfile installs the canon package at 0.1.5, but the model spec says de.bgb.fristen@0.1.0. Is that a mismatch?
No. 0.1.5 is the version of the package that delivers the canon; 0.1.0
is the version of the canon itself, which the application pins in
MODEL_SPEC. Package 0.1.5 carries model version 0.1.0.
- Bind input: from form fields to facts
- Quickstart for the same canon in a single file
- TypeScript SDK and loading and pinning for the contracts this chapter uses
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.