Second + final batch of the doc refresh. README + CLAUDE went out in
8c9ae29; deploy/nixos/README + obsolete-flow flags in 924844f. This
commit covers everything left.
docs/machine-installation.md
Was describing a manual AppImage scp deploy + a `lamassu-kiosk`
systemd unit that hasn't been the deployment path for months.
Replaced with a high-level "what the pipeline does and why"
overview that points at deploy/nixos/README.md for the full
command-by-command walkthrough. Includes the BATM3 chassis-mod
note (custom Dell OptiPlex retrofit, not a stock Dell).
docs/architecture-comparison.md
Rewrote the comparison to be lamassu-server (≤ v8.1.5) vs bitSpire
(LNbits-backed) instead of the original lamassu-server vs LP-backed
lamassu-next framing. Updated the cash-out + cash-in flow diagrams
to show the actual nostr-transport path (LNbits-bundled nostrrelay
extension at ws://<host>:5001/nostrrelay/test, no separate strfry
container). Replaced the migration-path section with a softer
"when to choose what" framing that includes Lamassu's current
commercial offering as a legitimate third option. Added a header
pointer to the Acknowledgements section.
docs/business-model.md
Light touch-ups: Lightning.Pub → LNbits where it appeared, swapped
the [[ndebit-cash-in-flow]] link for [[architecture-comparison]],
noted the kind-30078 service beacon for availability broadcasts.
docs/device-configuration.md
Dropped "Lamassu" branding from the machine-model headings
(Sintra / tejo / douro / batm3 are referenced by hardware identity
here, not by Lamassu's product line). Added the Sintra-specific
ttyS4-vs-placeholder-ttyS1..3 gotcha we hard-learned during the
first flash. Corrected the BATM3 entry: stock GeneralBytes chassis
with a Dell OptiPlex 9030 AIO motherboard physically grafted in,
NOT a Dell out of the box. Updated the example /dev/ttyJ* symlink
output to match what a healthy Sintra actually shows.
docs/adr/001-hal-architecture.md
ADRs are historical artifacts — kept the original decision text
intact. Added a postscript noting:
- The package rename @lamassu/hal → @bitSpire/hal
- The v8.1.5 boundary on any lamassu-machine source-tree
references (Lamassu's 2024-01-26 license transition)
- That the "Remaining Work" list is complete and the first
successful Sintra hardware integration ran on 2026-05-13
.claude/skills/lightning-check.md
Rewrote end-to-end. Was Lightning.Pub-flavoured with CLINK kinds
21001/21002 as the primary flows; now validates the LNbits nostr-
transport surface (kind-21000 envelope, NIP-44 v2 encryption,
subscribe_payments filter discipline, lnurlw link composition).
Preserved a --clink mode for the still-live kind-21003 operator-
management surface. Includes a "what to check" rubric for cash-out
vs cash-in flows that mirrors the actual code in
apps/machine/src/services/lightning.ts.
.claude/skills/hal-check.md
Two pivots: (1) acknowledge ADR-001's TypeScript-not-Rust choice
and reframe all the safety checklists in TS-flavour (type safety,
discriminated unions, single-writer serial, bounded emitters)
instead of Rust-flavour (unsafe, borrow checker). (2) Add explicit
v8.1.5 provenance boundary plus a "forbidden operations" section
that prohibits diffing or porting from v8.1.6+ lamassu-machine
source. Updated the port-validation source-reference table to
list TS file paths under packages/hal/ instead of Rust paths.
.claude/skills/docs.md
@lamassu/* → @bitSpire/*. Replaced the Lightning.Pub mermaid
diagram with a current cash-out flow showing the nostr-transport
RPC + subscribe_payments push path. Left the createOffer noffer
example in the API-docs template section since it's illustrative
("here's what a good TSDoc block looks like") rather than current
reference documentation.
.claude/skills/test.md
One-line: @lamassu/nostr-client → @bitSpire/nostr-client in the
pnpm-filter example.
deploy/nixos/README.md
Single touch-up: clarified the douro/batm3 hardware-module comments
to reflect that BATM3 is a custom-installed Dell board in a
GeneralBytes BATM3 chassis (not a Dell OEM).
Files NOT touched in this sweep (intentionally):
- packages/hal/src/**/*.ts attribution comments — those reference
"lamassu-machine" in their port-source headers. Those are
factually accurate (the drivers ARE ported from there, up to
v8.1.5) and constitute necessary license/attribution metadata.
Editing them would erase the provenance trail.
- .claude/skills/{nostr-check,security}.md — already protocol-
neutral, no LP/lamassu references to clean up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
157 lines
6 KiB
Markdown
157 lines
6 KiB
Markdown
# ADR-001: Hardware Abstraction Layer Architecture
|
|
|
|
**Status:** Accepted
|
|
**Date:** 2026-01-26
|
|
**Context:** Lamassu Next ATM proof of concept
|
|
|
|
## Decision
|
|
|
|
We will use **TypeScript HAL drivers extracted from lamassu-machine** rather than rewriting in Rust, and use **Electron instead of Tauri** for the kiosk application.
|
|
|
|
## Context
|
|
|
|
The Lamassu Next project needs to control ATM hardware (bill validators, dispensers) on Lamassu Sintra machines. Initial plans considered:
|
|
|
|
1. Rust HAL with Tauri backend
|
|
2. TypeScript HAL with Tauri (IPC bridge)
|
|
3. TypeScript HAL with Electron (direct integration)
|
|
|
|
### Hardware Target: Lamassu Sintra
|
|
|
|
- **Platform:** Aaeon UP Board (Intel Atom x5-Z8350, x86 Linux)
|
|
- **Bill Validator:** JCM iVIZION using ID003 protocol
|
|
- **Bill Dispenser:** Fujitsu F53/F56
|
|
- **Serial:** `/dev/ttyJ5` (validator), `/dev/ttyJ7` (dispenser)
|
|
- **Protocol:** RS-232, 9600 baud, 8 data bits, even parity, 1 stop bit
|
|
|
|
## Options Considered
|
|
|
|
### Option 1: Rust HAL + Tauri
|
|
|
|
**Pros:**
|
|
|
|
- Native Tauri integration
|
|
- Memory safety guarantees
|
|
- Single backend language
|
|
|
|
**Cons:**
|
|
|
|
- Requires full protocol reimplementation
|
|
- Two debugging environments (Rust + TypeScript)
|
|
- Serial at 9600 baud doesn't benefit from Rust performance
|
|
- Significant time investment with uncertain payoff
|
|
|
|
### Option 2: TypeScript HAL + Tauri
|
|
|
|
**Pros:**
|
|
|
|
- Reuse battle-tested lamassu-machine drivers
|
|
- TypeScript throughout application code
|
|
|
|
**Cons:**
|
|
|
|
- IPC boundary between Tauri (Rust) and HAL (Node.js)
|
|
- Serialization overhead and complexity
|
|
- Two processes to manage and debug
|
|
|
|
### Option 3: TypeScript HAL + Electron (Selected)
|
|
|
|
**Pros:**
|
|
|
|
- Direct `serialport` npm access in main process
|
|
- Single debugging environment (Chrome DevTools)
|
|
- All packages run natively (state-machine, HAL, lightning, clink)
|
|
- Mature ecosystem, well-documented edge cases
|
|
- Fastest path to working proof of concept
|
|
|
|
**Cons:**
|
|
|
|
- Larger binary size (~150MB vs ~10MB)
|
|
- Higher memory usage than Tauri
|
|
- Bundles Chromium
|
|
|
|
## Decision Rationale
|
|
|
|
### Why not Rust?
|
|
|
|
The JavaScript drivers in lamassu-machine have run in production for years. The complexity is in the protocol state machines (ID003 FSM, F56 DLE/STX framing), not raw performance. Serial communication at 9600 baud is trivial - Rust's performance benefits are irrelevant here.
|
|
|
|
Adding Rust creates a language boundary that requires:
|
|
|
|
- IPC serialization/deserialization
|
|
- Two build systems
|
|
- Two debugging environments
|
|
- Potential for bugs at the boundary
|
|
|
|
For a proof of concept, minimizing unknowns is critical.
|
|
|
|
### Why Electron over Tauri?
|
|
|
|
Tauri's benefits (small binary, low RAM) optimize for end-user desktop apps where download size matters. An ATM is a single-purpose kiosk:
|
|
|
|
- Binary size irrelevant - installed once on dedicated hardware
|
|
- RAM sufficient - Sintra has 2-4GB, not competing with other apps
|
|
- Development speed critical - proof of concept needs fast iteration
|
|
|
|
Electron allows the Vue UI, state machine, HAL, and Lightning packages to all run in the same Node.js environment with unified debugging.
|
|
|
|
## Implementation Status
|
|
|
|
### Completed
|
|
|
|
- `@lamassu/hal` package created with:
|
|
- ID003 bill validator driver (JCM iVIZION)
|
|
- F56 bill dispenser driver (Fujitsu F53/F56)
|
|
- TypeScript types for all interfaces
|
|
- Extracted from lamassu-machine, fully typed
|
|
|
|
### Remaining Work
|
|
|
|
1. Convert `apps/machine` from Tauri to Electron
|
|
2. Wire HAL to state machine services:
|
|
- `dispenseCash` → F56Dispenser.dispense()
|
|
- Bill events → state machine events
|
|
3. Add device configuration (serial port paths)
|
|
4. Test on physical Sintra hardware
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
|
|
- Faster proof of concept development
|
|
- Easier debugging during hardware integration
|
|
- Reuse of proven driver code
|
|
- Single language throughout
|
|
|
|
### Negative
|
|
|
|
- Larger deployment size (acceptable for kiosk)
|
|
- Cannot leverage Rust safety guarantees (mitigated by mature JS drivers)
|
|
|
|
### Future Considerations
|
|
|
|
If a compelling reason for Rust emerges (it likely won't), the HAL interface is abstracted - drivers could be reimplemented without changing the state machine integration. The Vue UI works with either Electron or Tauri.
|
|
|
|
## References
|
|
|
|
- `packages/hal/` — TypeScript HAL implementation
|
|
- `packages/state-machine/src/types.ts` — ATMServices interface
|
|
- `deploy/nixos/hardware/upboard.nix` — Sintra device paths and udev rules
|
|
- lamassu-machine `lib/id003/`, `lib/f56/` — Original JS drivers (v8.1.5 release line and earlier; see postscript below)
|
|
|
|
---
|
|
|
|
## Postscript (2026-05-13)
|
|
|
|
This ADR is still in effect — TypeScript HAL in Electron remains the right call for the same reasons documented above. A few clarifications for readers in 2026 and beyond:
|
|
|
|
1. **Package naming.** The HAL package was originally `@lamassu/hal` (per the line above in "Completed"). It was renamed to `@bitSpire/hal` during the project rename from `lamassu-next` to `bitSpire` (commit `924844f` in the 2a sweep). All references to the package scope should now read `@bitSpire/hal`.
|
|
|
|
2. **Source-tree provenance, post-Lamassu license change.** The "Original JS drivers" reference above refers to lamassu-machine's `lib/id003/` and `lib/f56/` directories in the **v8.1.5 release line and earlier**, which were published under a fully-open license. Lamassu Industries AG transitioned to a proprietary source-available license on 2024-01-26 (v8.1.6+). bitSpire incorporates no code from v8.1.6 or later; the protocol-level reimplementations we have are derived from v8.1.5 + protocol specs published by JCM, Fujitsu, etc. See [CLAUDE.md → Provenance + legal status](../../CLAUDE.md#provenance--legal-status) for the operating rules going forward.
|
|
|
|
3. **Implementation status.** The "Remaining Work" list above is complete:
|
|
- `apps/machine` runs on Electron (the original Tauri scaffolding was removed early on)
|
|
- HAL is wired to the state machine via the ATMServices interface
|
|
- Device configuration ships via `deploy/nixos/hardware/upboard.nix` + the `services.bitspire` NixOS module
|
|
- First successful Sintra hardware integration test ran on 2026-05-13 (cash-out flow verified end-to-end against a regtest LNbits instance)
|
|
|