Claude Code keeps per-project memory at <home>/.claude/projects/<key>/,
where <key> is the project's absolute path with every separator and the
drive colon turned into a dash. That makes it both rename-fragile and
machine-specific, and this project has hit each of those once:
- D:\DEV\Schunix -> D:\DEV\SchOS changed the key, and 43 memories were
invisible until moved across by hand.
- Development happens from Windows and from Linux, and each looks in a
different place for the same checkout.
Committing .claude/memory/ fixes both -- git carries it across renames
and between hosts -- and `import` puts it wherever the local machine
expects. .claude/settings.local.json stays ignored: those are per-machine
permissions.
The colon maps to a dash rather than being dropped. Deleting it gives
D-DEV-SchOS, which matches nothing and silently finds zero memories; that
was the first attempt. On Git Bash the key comes from `cygpath -w`,
because Claude Code is a Windows program and sees D:\DEV\SchOS, not
/d/DEV/SchOS.
3.6 KiB
| name | description | metadata | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| schunix-boot-splash-logo | The boot logo pipeline, why the loader draws it rather than the kernel, and the STAGE2_SECTORS trap that consolidating it exposed. |
|
The boot splash shows the Assets/Schunix Small Logo.png mark (an SX monogram in
a ring) above the S C H U N I X wordmark and its accent rule, all centred as
one group. Verified rendering correctly on 2026-08-08.
The logo is drawn by the bootloader, not the kernel. This is the
counter-intuitive part and it is a timing fact, not a preference: the kernel does
not reach vga_init() until roughly the last 300ms of a ~2.8s boot, so a
kernel-drawn logo appeared for about one frame before console_takeover() wiped
it. Drawn from splash() in boot/stage2main.c it is up for the whole boot.
kernel/dev/vga.c keeps the same drawing code against the same mask
(vga_draw_logo, vga_logo_centered) for things that want the mark after
boot — the crash screen, eventually schinit. Don't "fix" the duplication by
deleting the loader's copy.
Pipeline: tools/mklogo.py (host Python, has its own PNG inflate +
un-filter) crops to the mark, box-downscales, normalises to full strength, packs
to a 4-bit coverage mask, and writes include/logo.h. Run make logo — it is
not a build dependency, and include/logo.h is committed, on the same
reasoning as include/font.h. The mask is coverage, not colour, so the palette
stays in schunix-console-tty's include/theme.h; the loader composites it in
SCH_FG because the source art is a silver gradient and the accent is reserved
for the one rule. 4 bits rather than 8 because the header is included by the
bootloader, where size is a boot constraint.
STAGE2_SECTORS was encoded in five places, not the three docs/layout.md
claimed. Raising it 24 → 48 to fit the 8 KiB mask proved it: the dd seek=25
offset stayed behind and the kernel got written straight over stage2's tail.
The five were boot/bootasm.S, boot/stage2main.c, the dd seek=, and twice
inside tools/mkiso.sh (its size assertion and -boot-load-size). It now lives
only in the root Makefile, which passes -DSTAGE2_SECTORS and exports it to
mkiso; the #defines left in the boot sources are #ifndef fallbacks. Hard
ceiling is 65 sectors — stage2 loads at 0x7E00 and must not reach the
multiboot kernel-search buffer at 0x10000 — and stage2main.c now
static-asserts that. See also schunix-iso-boot.
tools/splashshot.ps1 captures a burst of QEMU screendumps across early
boot and reports each frame's distinct-colour count, because the splash window
is too short to hit with a single guessed delay. It uses -snapshot plus
file.locking=off so it runs while an interactive QEMU has the images open —
booting from copies also works but means duplicating all 153 MB of
build/fs.img per run. Colour counts are the
assertion: ~2 means text console or blank, 18 means the 4bpp logo is up. If it
ever reads 156 again, something is drawing an 8-bit mask.
Two traps, both hit while doing this:
$(shell expr $(N) \* 512)in a Makefile does not work — make passes the backslash through, sh globs the*, and expr receives a directory listing. Make silently carries on with nonsense. Use$$(( ))in the recipe.make isowas failing when this was written, for unrelated reasons since fixed — see schunix-ramdisk-root-sizing.-boot-load-size 49is now verified: the ISO boots from optical media only.