nandi/frqpublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

CLAUDE.md · 114 lines · 5.0 KBmarkdown Blame HistoryRaw
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 18d ago1# Working in this repo
2
Six verbs, and the last of the nix 2e24e64 nandi 7h ago3## The toolchain, and where builds happen
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 18d ago4
The last of the Clojure 284b59c nandi 27m ago5There is no nix in the build. `tools/toolchain.sh` fetches Flutter (which
6carries Dart) and Nim as sha256-pinned tarballs into `.toolchain/`, and every
7`just` recipe runs inside the environment that script prints. The host brings
8a C compiler, OpenSSL, git, curl, unzip and python3 — and GTK with the usual
9CMake/Ninja/pkg-config for the Linux target.
10
11It used to carry a JDK, the Clojure CLI, a maven repo and an Android SDK as
12well. Those were ClojureDart's and the APK's, and both are gone.
Six verbs, and the last of the nix 2e24e64 nandi 7h ago13
14**Prefer Modal for a long build.** A cold Flutter toolchain plus a full
15compile is a lot of laptop, and the containers in `.modal/` do it on a real
16machine:
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 18d ago17
18```bash
Six verbs, and the last of the nix 2e24e64 nandi 7h ago19just modal dev # the incremental Flutter loop
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 18d ago20```
21
One frontend where there were three, and a core that is not Clojure 438b247 nandi 11h ago22The containers in `.modal/` are not a third source tree: they are CI config
Six verbs, and the last of the nix 2e24e64 nandi 7h ago23that happens to live here, the way `.github/` would be. They run the very same
24`tools/toolchain.sh`, which is why a plain Debian image is enough.
Build the window somewhere with room for it 1451151 nandi 5d ago25
26`modal app logs` is no substitute for watching that command: it resolves
27deployed apps by name, not the ephemeral one a `modal run` creates, and carries
28nothing until the Sandbox starts — the image build streams to the client and
29nowhere else.
30
Six verbs, and the last of the nix 2e24e64 nandi 7h ago31The containers run as Modal **Sandboxes on a real VM** rather than under
32gVisor: a real kernel, a working pty, and memory that is exactly what
33`[resources] memory` asks for.
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 18d ago34
Follow the xorg renames, and stop wrapping nix in distrobox a400a00 nandi 16d ago35One thing this container is *not* representative of: `/etc/localtime` is a
36regular file here rather than a symlink, so anything that reads the zone out
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 18d ago37of its path sees nothing. That is a real deployment shape, not an artefact —
38frq.clock handles it.
Split the tree three ways, and let the phone be Flutter's 7070931 nandi 7d ago39
Build the window somewhere with room for it 1451151 nandi 5d ago40## Never pipe a long task through `tail`
41
42`tail` and `head` do not emit anything until their input ends, so a build, a
43test run or a deploy piped through one shows nothing at all until it is over —
44and if it is killed or times out first, its output is lost with it. That is the
45opposite of what you want from the commands that take longest.
46
47Let them write to the terminal, or `tee` them if you want a copy to grep
48afterwards:
49
50```bash
Six verbs, and the last of the nix 2e24e64 nandi 7h ago51modal run .modal/web/container.py 2>&1 | tee /tmp/frq-build.log
Build the window somewhere with room for it 1451151 nandi 5d ago52```
53
54Trim afterwards, on the file, where the whole run is still there to re-read.
55The same goes for `grep` and `awk` in a live pipeline: they buffer when their
56output is not a terminal, so pass `--line-buffered` / `fflush()` or watch the
57file instead.
58
One frontend where there were three, and a core that is not Clojure 438b247 nandi 11h ago59## The Nim core
60
The last of the Clojure 284b59c nandi 27m ago61`nim/` is the program. It owns the state, the screens, the IRC connection and
62the signing; Flutter is a renderer over the widget tree it emits. Read
63`nim/README.md` before touching it.
One frontend where there were three, and a core that is not Clojure 438b247 nandi 11h ago64
65Two rules the ABI has, both of which cost a segfault to rediscover:
66
67* Every string the core returns is the **caller's** to free, with `frq_free`.
68 Nim's allocator is not Dart's.
69* `frq_init` runs once before anything else.
70
The last of the Clojure 284b59c nandi 27m ago71`dart/frq_core` is the other half of that seam. It is a plain Dart package and
72not a Flutter one, deliberately: `flutter/pubspec.yaml` depends on the Flutter
73SDK, so anything living there needs a Flutter toolchain to check one assertion
74about a string, where this resolves and tests on its own.
75
76The rule that used to be here said new Dart-side code is written in Dart
77rather than ClojureDart. There is no ClojureDart left for it to rule against,
78but the reasoning it rested on still holds for the next thing: logic goes in
79Nim, the platform goes in Dart, and neither is written in a third language
80because it is already open.
The binding is Dart, and it works f7aea3b nandi 11h ago81
Six verbs, and the last of the nix 2e24e64 nandi 7h ago82`just test nim` and `just test dart` need no Flutter, which is most of the
The binding is Dart, and it works f7aea3b nandi 11h ago83point: the whole boundary is checkable in about a second.
One frontend where there were three, and a core that is not Clojure 438b247 nandi 11h ago84
The last of the Clojure 284b59c nandi 27m ago85There is no `common/` any more, and that rule went with it. It said a module
86stays until there is a wasm build of the core, because a browser has no
87dart:ffi — which was true, and the web target is gone rather than the rule
88being wrong. Bringing it back means compiling the core to wasm, not restoring
89ClojureDart.
One frontend where there were three, and a core that is not Clojure 438b247 nandi 11h ago90
The last of the Clojure 284b59c nandi 27m ago91## The source trees
Split the tree three ways, and let the phone be Flutter's 7070931 nandi 7d ago92
93```
The last of the Clojure 284b59c nandi 27m ago94nim/ the program: state, screens, IRC, signing
95dart/frq_core the FFI binding — plain Dart, not a Flutter package
96flutter/lib the renderer, and the app's entry point
Split the tree three ways, and let the phone be Flutter's 7070931 nandi 7d ago97```
98
The last of the Clojure 284b59c nandi 27m ago99`nim/src/frq/ui.nim` builds a widget tree; `frq_core` carries it across the
100FFI as JSON; `flutter/lib/nim_renderer.dart` walks it into Flutter widgets.
101The renderer knows the tag vocabulary and nothing else — no screens, no state,
102no idea what "connect" means. If a feature ever needs a change on both sides,
103the boundary is in the wrong place.
104
105There used to be two more trees. `src/` was jolt and libcosmic; `common/` and
106`flutter/src/` were ClojureDart, compiled for Android, Linux and the web. Both
107are gone, and with the second went the APK and the web target: a browser has
108no `dart:ffi`, and the APK wants `libfrqcore.so` cross-compiled for Android's
109ABIs. What is left builds one thing, `just build desktop`.
110
111Two modules were never ported and are gone rather than moved: `frq.profile`
112(the Bluesky profile behind a nick) and `frq.replies` (asking freeq what a
113collapsed msgid was). Neither had a screen in the Nim app to appear on.
114