Repository navigation
First-run funnel: the REPL never teaches the commutative field calls, and the README buries the use case #548
Description
Found by running the published quickstart cold on a clean machine, as a first-time visitor would.
The product works
docker run -it --rm ghcr.io/orlyatomics/orly repl connects and answers in ~2s (even on Apple Silicon, under emulation). *<['hits']>::(int) += 1 twice then a read gives 2, and set-union gives ["blue","green"] — upserting from the monoid identity with no new. The headline property is real and immediately demonstrable.
But the first thing a visitor tries fails
The REPL's own :help teaches assignment and read:
(true) effecting { new <['k']> <- 1; }; write through the pov
*<['k']>::(int); read it back
It never shows += or |= — the commutative field calls the project is pitched on, the first thing in the README, and the entire content of the announcement thread.
So the natural move is to take the help's write form and substitute the feature from the pitch:
orly> (true) effecting { <['counter']> += 5; };
2:37-2:56 [orly/type/add_visitor.h, 50]This expression is invalid.
orly> *<['counter']>::(int);
0
Three problems in four lines:
- The correct form needs a leading
*and a::(type)annotation, and nothing on the path says so. - The diagnostic leaks an internal C++ header path and line number (
orly/type/add_visitor.h, 50) with no explanation of what is invalid or how to fix it. - The follow-up read returns
0rather than an error, so it reads as "the write landed and the data is wrong".
The README compounds it
The announcement asked "how do I give my agents shared memory". The README opens with "a non-relational database built around Points of View, causally-ordered merge, and a compiled query language", and the first substantive paragraph is that the project was dormant from 2019. agent first appears meaningfully at line 167 of 250; the MCP server — the path that delivers value without learning orlyscript at all — is a parenthetical inside a Docker paragraph.
Scope
-
:helpteaches+=and|=with the*<[...]>::(type)form and the identity-fold note — repl+docs: teach the commutative field calls, and lead the README with the use case (#548) #549 - README leads with the use case; MCP promoted to a first-class quickstart; dormancy status moved out of first position — repl+docs: teach the commutative field calls, and lead the README with the use case (#548) #549
- Publish a multi-arch image so Apple Silicon stops printing a platform-mismatch warning on the headline command — docker: build and publish a multi-arch image (#548) #552, merged 2026-09-16
- Separately: the compiler diagnostic should not surface internal header paths to users — now Compiler diagnostics leak internal C++ source paths to users (
[orly/type/add_visitor.h, 50]) #557
The first two are small and sit exactly on the path between "interesting post" and "aha". The last is a real diagnostics change and wants its own issue if picked up.
Status 2026-09-16. The first two shipped in #549. The multi-arch image (#552) turned into a
longer detour than expected: the arm leg of the docker build was blamed in turn on memory
pressure, on QEMU, and on aarch64 LTO codegen being ~18x slower. All three were wrong. It was a
genuine bug — orlyc deadlocking on aarch64 (#554), a fiber reading a cached thread pointer
after migrating OS threads, fixed in #555.
With that in, the arm64 image job is 9m48s end to end, faster than amd64's 12m04s, every smoke
included. There was never anything slow about aarch64 here.
The fourth item is now #557: Base::AsStr(code_location, message) in orly/error.h bakes the
C++ TCodeLocation into the exception message, so every consumer inherits it — both orlyc's
stderr and the WS reply the REPL and MCP server read.
2026-09-16: #552 merged. Worth being precise about what that does and does not do. The
workflow builds both arches natively and runs every smoke on each, but docker.yml only
publishes on a v* tag or a manual dispatch — a push to master triggers nothing. So
ghcr.io/orlyatomics/orly:latest is still the amd64-only image from two months ago, and Apple
Silicon still gets the platform-mismatch warning on the headline command until the next tagged
release (or a deliberate dispatch). The box above is ticked for the work; the user-visible
symptom that opened this issue clears at publish.
Activity
build: drop -msse2, a no-op on x86-64 and fatal on aarch64 (#548)
ci: the aarch64 job needs valgrind too (#548)
Merge pull request #549 from orlyatomics/fix/548-first-run-funnel
docs: record that aarch64 builds and tests clean (#548)
portability: replace the only x86-specific code with __builtin_prefet…
build: drop -msse2, a no-op on x86-64 and fatal on aarch64 (#548)
ci: the aarch64 job needs valgrind too (#548)
docs: record that aarch64 builds and tests clean (#548)
Merge pull request #550 from orlyatomics/feat/548-arm64-portability
docker: build and publish a multi-arch image (#548)
docker: report runner capacity, and tune the arm build per-arch (#548)
ci: one-shot profile of where the aarch64 release build spends its ti…
ci: let the profile workflow run from this branch (#548)
docker: pin the build platform, and find out if the arm image build w…
ci: minimal repro for the orlyc hang on aarch64 (#554)
Merge pull request #552 from orlyatomics/feat/548-multiarch-image
ohohoreilly commentedon Sep 17, 2026
Published, and the symptom is gone
docker.ymldispatched on master: both arches built natively, every gate ran on each image (MCP smoke, in-containerorlyccompile, REPL mode), and:latestwas stitched into a real manifest list.And the thing this issue was actually about — the README's headline command, run on an Apple Silicon machine, no
--platform, nothing special:No platform-mismatch warning, no emulation. Closing on that rather than on the merge.
Two things the publish turned up
The manifest verification was broken and failed the very run it was meant to protect. It grepped
'"architecture":"[a-z0-9]+"'againstimagetools inspect --raw, which pretty-prints — the bytes are"architecture": "amd64", with a space — so it matched nothing while the manifest it was checking was perfectly correct. It had never executed before, because that job only runs on a dispatch or av*tag and neither had ever happened. #559 replaces the grep with ajqparse, checked in both directions against the live registry.The arm REPL smoke flaked once, on the first dispatch: connected, took a pov, then 29 seconds of silence and
orly: websocket closed. It passed on the immediate re-run, passed on #552's own run the day before, and passes locally against the published arm image — so 1 in 4, not a regression. Worth knowing that the job'sContainer logs (for diagnosis)step cannot see it either way: it tails the long-livedorlycontainer from the MCP smoke, while the REPL step starts its own ephemeraldocker run --rm. If that flake recurs, fixing the diagnostic is the first move.Remaining scope
Nothing here. The fourth item went to #557 (compiler diagnostics leaking internal C++ paths), which is unrelated to the first-run funnel except that the funnel is where it was noticed.
Note this publishes
:latestonly. The repo still has nov*tags, so there is no versioned image — a deliberate choice, not an oversight, and a separate decision from this issue.