# 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 - **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 `curl` and `unzip`; no repository checkout. Versions are listed in the [route overview](/build/). - **Run:** ```bash curl -O https://docs.arxo.io/build/deadline-app-0.1.0.zip curl -O https://docs.arxo.io/build/deadline-app-0.1.0.zip.sha256 shasum -a 256 -c deadline-app-0.1.0.zip.sha256 unzip -q deadline-app-0.1.0.zip cd deadline-app npm ci npm test npm start ``` - **Files:** this chapter changes nothing; it runs what the archive contains. ```text (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 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](#choose-a-node-version) below gives the support dates. ## Download and verify the archive Download and verify the versioned archive (example 0.1.0): ```bash curl -O https://docs.arxo.io/build/deadline-app-0.1.0.zip curl -O https://docs.arxo.io/build/deadline-app-0.1.0.zip.sha256 shasum -a 256 -c deadline-app-0.1.0.zip.sha256 ``` Expected: `deadline-app-0.1.0.zip: OK`. (On Linux the same check is `sha256sum -c`.) The verified checksum is: ```text 4b8186fcb2caedf9316ff02fdca7032c6713bddc1fe672713fb44eebe0950411 ``` ## Install the pinned dependencies Unpack and install the pinned dependencies from the lockfile: ```bash unzip -q deadline-app-0.1.0.zip cd deadline-app npm ci ``` `npm 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 Run the suite — a separate step, before any server: ```bash npm test ``` ```text # tests 63 # pass 63 # fail 0 ``` 63 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 Start the server — it runs in the foreground, so this is its own terminal step: ```bash npm start ``` ```text deadline-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: ```bash node --import tsx src/cli.ts evaluate --event 2026-03-06 --days 14 node --import tsx src/cli.ts evaluate --event 2026-03-06 --days 14 --candidate 2026-03-20 ``` The 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: ```text The period ends on 2026-03-20 Computed from the event date and the duration by the pinned canon. rules: TagesfristEnde sources: No sources anchored in this canon build — the rule names above carry the provenance. program: sha256:468e3fe17c6a28371c6ce8258ae7928c496593673d4b73a52c2a9c40cb50ee33 semantic: sha256:90e53b453107dfee9422a5fe24774823430b5c82c3577b9321a0838a6e54c695 result: sha256:ae9a7b19361154c868eb9b28d5ac6395b1d2844053259a1abfd6f75e300de812 ``` The second call checks the proposed date and establishes it: ```text Yes — the proposed date is established The engine established that the period ends on the proposed date. rules: TagesfristEnde ``` `TRUE_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 The model spec names the exact canon version the application pins. It lives in one place, beside the deadline policy and the time zone: ```ts // src/to-case.ts 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: ```ts // src/runtime.ts // Calculate mode: which date(s) end the period? export async function evaluateCollect(input: FormInput): Promise { 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 { const model = await openModel(); const query = buildTruth(candidate); return model.truth(query.predicate, query.args, toCaseInput(input)); } ``` ## 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 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 The server binds loopback only and defaults to port 8787; `HOST` and `PORT` override both: ```ts // src/server.ts // 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 - A checksum mismatch on the download means a corrupt or substituted file: re-download, do not proceed. - `PackageNotFound` on `openModel` means the canon package is not installed. The fix is `npm ci`, not a looser version. - Node below 20 is outside `engines` (`>=20`), but that field alone only warns: without `engine-strict` npm installs anyway, and the starter ships no `.npmrc` to 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 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: ```bash node --import tsx src/cli.ts evaluate --event 2026-03-06 --days 14 --candidate 2026-03-21 ``` ```text Not established either way The engine neither established nor refuted the proposed date; it does not guess. rules: TagesfristEnde ``` Before 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.
## Next - [Bind input: from form fields to facts](/build/bind-input/) - [Quickstart](/guide/quickstart/) for the same canon in a single file - [TypeScript SDK](/build/sdk/typescript/) and [loading and pinning](/build/sdk/loading-and-pinning/) for the contracts this chapter uses