Start notebooks with import gemdb, and fix three things the CLI got wrong - #16
Merged
jgfoster merged 1 commit intoAug 27, 2026
Conversation
…rong Four changes a user ran into in one sitting. **The sample code says `import gemdb`.** A new notebook's first cell, the walkthrough and the README all opened with `import gemstone` -- Grail's own lower-level surface, inherited from Jasper. `gemdb` is the module a developer should meet first: `gemdb.root` for the data that outlives the session, `gemdb.commit()` for the moment it becomes everyone's. **`gemdb` is on the PATH of terminals opened in VS Code.** The command is generated into `~/GemDB/bin`, which is on nobody's PATH, so `which gemdb` answered "not found" and the README's answer was a line the user had to add to their own shell profile. VS Code contributes this per extension and reverts it when the extension is disabled, which keeps it on the automated side of the line; editing a shell profile would not be, so that stays an ask. Cleared before every prepend, because the collection is persisted across window reloads and re-applied before activation. **topaz no longer comments on an exit it was always going to ignore.** `gemdb file.py` from a real terminal ended with four lines about ignoring an EXIT and a `Logging out session 1.`. `topaz -h` says of `-S` that topaz "exits when the script completes" and that "exit and quit commands are ignored" -- silently on a pipe, which is every CI run and both suites, and out loud on a tty. Exit codes never travelled through that line and still do not: sys.exit(3) -> 3, an uncaught exception -> 1, a missing file -> 2, measured again over a pty without it. **Non-ASCII survives `gemdb file.py` in both directions.** The console this mode installs is a GsFile, which takes BYTES: print() wrote a Unicode string's code units, so a bullet in an ASCII-art rabbit came out as binary. The #GrailConsole box gains a second slot naming what the sink takes, because the sink cannot be asked -- the shell's is a ClientForwarder, and any send to one forwards to the client as error 2336, uncatchable in the gem. Needs the matching Grail change (GemTalk/Grail#701), which also decodes the mirror-image fault on the read side: a line typed at the terminal arrived one character per byte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #15 — the
cli.tschanges here sit on top of its restaging work. Merge #15 first, deleting its branch, and GitHub retargets this tomainautomatically (it only auto-retargets when the base is deleted).Four things a user ran into in one sitting.
The sample code says
import gemdbA new notebook's first cell, the walkthrough and the README all opened with
import gemstone— Grail's own lower-level surface, inherited from Jasper.gemdbis the module a developer should meet first:Run verbatim through the staged shell before being written down — the last line really does display
'Hello from GemDB!'.gemdb.rootrather than a bare subscript is the better first impression anyway, becauserootis what makes persistence visible, and it matchesdocs/demo/, which already usedgemdb.gemdbis on the PATH of terminals opened in VS CodeThe command is generated into
~/GemDB/bin, which is on nobody's PATH, sowhich gemdbanswered "not found" and the README's answer was anexport PATH=…line the user had to add to their own profile.putCliOnPathcontributes it tocontext.environmentVariableCollection. That stays on the automated side of the line in CLAUDE.md: it applies only to terminals this editor launches, VS Code reverts it when the extension is disabled, and nothing outside~/GemDBis touched. Editing a shell profile would be the other side — persistent, global, not ours to undo — so the README still asks for that one.clear()before everyprepend, because the collection is persisted across window reloads and re-applied before activation: without it a reload stacks a second entry, and a changedgemdb.rootPathleaves the old one in front. Applied after the platform gate, and beforebin/gemdbexists, so a terminal opened during first-run setup finds the command once setup writes it.topaz no longer comments on an exit it was always going to ignore
gemdb file.pyfrom a real terminal ended with:topaz -hsays of-Sthat topaz "exits when the script completes" and that "exit and quit commands are ignored". Ignored silently on a pipe — which is every CI run, both suites, and everygemdb x.py | cat— and out loud on a tty. The ignored EXIT is also what provoked theLogging out session 1.Exit codes never travelled through that line and still do not, re-measured over a pty without it:
sys.exit(3)→ 3, uncaught exception → 1 with the message on stderr, missing file → 2,-c→ 0.input()from a terminal still works.Non-ASCII survives
gemdb file.pyin both directionsThe console this mode installs is a
GsFile, which takes bytes, andnextPutAll:writes a Unicode string's code units straight through. A•in the demo's ASCII-art rabbit turned the whole drawing into binary:The
#GrailConsolebox gains a second slot naming what the sink takes. The sink cannot be asked: the shell's is aClientForwarder, and any send to one —class,respondsTo:,isNil— forwards to the client as error 2336, which is not a Smalltalk exception and is not catchable in the gem (measured). A probe would turn every print in a streaming session into a spurious client stop.wörldsix characters long, mojibake on the way back). CI here is red until that lands, sincebundle:grailclones Grail's default branch; prove it green meanwhile withworkflow_dispatchandgrail-ref: fix/console-utf8-for-byte-sinks.Verification
putCliOnPath(through a fake collection, in theStopWorldstyle), for the driver carrying noexit, and for the#'utf8'slot.One commit rather than four: splitting it would have meant reconstructing intermediate versions of five files that every topic touches.