Merges StarForth-v4.0.0 into master: StarForth v4 as the default system, the tree reorganised
(v3/, kernel/, boards/), the stick and the identity gate, and the day's CI -- the acceptance gate,
the nightlies and release to Nexus. Closes#19, #18.
Accepted by acceptance.yml, run 153, on 0fd7648a: amd64, aarch64, riscv64 to [zuse@Hera] ok>, the
PC stick loaded high (the three agree on dict_hash), make -C v4 test-32 -- the first acceptance
run in CI. The quick checks (run 152) passed too.
Captain Bob, 2026-11-06: what a developer runs, what CI runs and what
the nightly runs are one process, and "failures should not be allowed
to be merged to master".
acceptance.yml runs on every PR into master (opened, pushed to,
reopened): .claude/CLAUDE.md's acceptance protocol through the same
scripts/nightly.sh stages -- amd64, aarch64, riscv64 to [zuse@Hera]
ok>, the PC stick loaded high (and the three agree on dict_hash), then
make -C v4 test-32 -- one QEMU at a time, in one job. Its logs and DoE
CSVs are kept, pass or fail. master's branch protection requires it.
acceptance, nightly and release share the concurrency group qemu, so
the runner never runs two of them at once: CLAUDE.md's one-QEMU rule
holds in CI too. build.yml becomes the quick check on pushes only.
.claude/CLAUDE.md's Hard Rules: commit and push directly on the working
branch; master only through a PR that passed acceptance, no direct
pushes; no approval required while there is one developer. Named: the
Captain Bob method.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
build.yml, as master had it, could not run here: it called
Makefile.starkernel and make T=<board> (the tree has kernel/Makefile
and TARGET=<board>), listed a Pi 4 with no port, published "releases"
under org/f18 on every push, installed Isabelle2024 (the proofs need
Isabelle2025-2) from a mirror that answered 503, and duplicated the
nightlies with its own 02:00 schedule. Now it is the check on every
push to master and StarForth-v4.0.0 and every PR into master: each
board's image (make boot_image TARGET=PC|RASPI|MILKV, xz'd, kept with
its SBOM) and make -C v4 test, both cell widths. It publishes nothing;
the nightlies and release.yml do.
Every job of every workflow now names its container,
gitea/runner-images:ubuntu-24.04-v26.11.03: the runner maps
ubuntu-latest to node:20-bullseye, Debian 11, where every job of PR
#30's runs failed at its first apt-get, and which has no
qemu-efi-riscv64 and a far older QEMU and compilers than the Ubuntu
24.04 all of this was tested on. Node is needed in the image:
actions/checkout and upload-artifact run inside the job's container.
The dated tag keeps a run from changing under an image update.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
For PR #30. master's 9 commits since the fork (T= board selection,
mk/boards.mk, build.yml, the nightly workflows) conflicted in four
files; each is resolved to the branch's version:
.gitea/workflows/nightly.yml added on both; master's copy named
.gitea/workflows/nightly-docs.yml the branch in its checkout, the
branch's builds the default branch
Makefile master's T= and mk/boards.mk against
kernel/Makefile the branch's TARGET=<board> and
boards/; master's edits were to
Makefile.starkernel, renamed here
The two workflows' header comment now says they build master.
Merged cleanly from master: build.yml (its board matrix, Nexus publish
and 02:00 nightly; it still calls Makefile.starkernel and make
T=<board>, which this tree does not have -- #18) and mk/boards.mk
(nothing here includes it).
Against the branch the merge changes only those CI files and
mk/boards.mk: no kernel, v4 or Makefile source, so the build is the one
accepted on 2026-11-06.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
From /doctor's review: .claude/CLAUDE.md (40206 chars) was at the size
Claude Code warns about, and is read at the start of every session.
Now 30973.
Cut, as a session can read them from the tree itself: the Source Tree
listing, the boot-sequence diagram, "Key distinguishing features" and
License. The listing's two facts the code does not tell -- the stale
"M7: Not started" header in kernel_main.c, and virtio_blk.c not
meaning M9 is done -- are kept, as "Gotchas in the tree".
Moved, word for word, to files that load only when working there:
"Physics-Driven Adaptive Runtime" and "Critical Implementation
Details" to v3/CLAUDE.md; the superseded ACL-RWT DoE campaign
history to experiments/bare_metal/CLAUDE.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
logs/20261106-151805: scripts/nightly.sh proofs before -c was added. The
StarForth session's sources were unchanged since the day's earlier build,
so Isabelle reused its result and proved nothing anew (0:00:10). Kept as
the record of that run; the stage now passes -c, and the run after it
(20261106-151902) checked StarForth afresh.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
scripts/nightly.sh, one stage per call, a step each in the workflows:
accept <amd64|aarch64|riscv64|stick-high> the acceptance protocol --
qemu_session.py zuse, and stick_zuse --target qemu-stick-high;
after the last, dict_hash must be equal on the three
test-32 make -C v4 test-32
proofs isabelle build -c -D proof/ (StarForth checked afresh each run)
images the Pi 5 and Mars images, xz for Raspberry Pi Imager
publish org.starship:kernelImage: pc (iso), raspi5, milkv (img.xz),
logs (tar.gz: this run's serial logs, proof log, DoE CSVs)
docs, publish-docs book, vol1-3, api -> org.starship:documentation
.gitea/workflows/nightly.yml (03:00) and nightly-docs.yml (04:00) publish
<LITHOS_VERSION>-SNAPSHOT to starshipos-snapshots; release.yml, on a tag
v*, builds and publishes both to starshipos-releases at the tag's version,
refusing a tag that is not v<LITHOS_VERSION>. Until this branch is merged
to master, master carries copies of the two nightlies naming it.
make init: INIT_DOCS=0 leaves out TeX and Doxygen, INIT_PROOFS=0 Isabelle.
Checked here, stage by stage, in order: the four acceptance boots PASS,
dict_hash 0xfec8c47cfc6f437f on the three, test-32 0 failures, StarForth
proved (0:00:41), images built; publish to a local file:// repository,
and the images' publish to Nexus starshipos-snapshots read back byte for
byte. The docs stage and publish-docs: not yet checked when committed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Gitea runs schedules from the default branch only, so until StarForth-v4.0.0
is merged here, master carries copies of that branch's two nightly
workflows, identical to them but for the checkout's ref:
nightly.yml 03:00 UTC: the acceptance protocol (zuse amd64, aarch64,
riscv64; the PC stick loaded high; dict_hash equal on the
three; test-32), the Isabelle/HOL proofs, the board images,
then org.starship:kernelImage:<LITHOS_VERSION>-SNAPSHOT --
classifiers pc (iso), raspi5, milkv (img.xz), logs
nightly-docs.yml 04:00 UTC: the book, the formal volumes, the API reference
-> org.starship:documentation:<LITHOS_VERSION>-SNAPSHOT
Both publish to starshipos-snapshots as ci-publisher (secret
NEXUS_CI_PASSWORD), and only if every stage before passed. The work is that
branch's scripts/nightly.sh. At the merge, take that branch's copies (this
ref line goes). build.yml's own 02:00 schedule is untouched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Three stages, each a step of the nightly workflow:
boot <amd64|aarch64|riscv64> qemu_session.py headless, one QEMU at a time,
in the acceptance order; amd64 keeps the ISO it
booted as build/nightly/StarshipOS.iso
images make boot_image for RASPI (Pi 5) and MILKV
(Mars) -> raspi5.img.xz, MilkV.img.xz (for
Raspberry Pi Imager), and SHA256SUMS
publish <url> mvn deploy:deploy-file (maven-deploy-plugin
3.1.2): org.starship:kernelImage:
<LITHOS_VERSION>-SNAPSHOT, classifier pc (iso),
raspi5 and milkv (img.xz), in one deploy
Classifier by board, not ISA: two aarch64 boards would collide. No Pi 4:
there is no BCM2711 port. QEMU boots the aarch64 and riscv64 kernels, not
the Pi 5 and Mars images, which are for hardware QEMU does not model.
make init takes INIT_DOCS=0: without the TeX and Doxygen packages and
Isabelle, which an image build does not need.
Checked here: the three boot checks pass (logs in the next commit), the
images build, and publish to a local file:// repository gives the
timestamped snapshot files, the POM and maven-metadata.xml with one
snapshotVersion per classifier. Not checked: Nexus itself.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Scheduled runs use -SNAPSHOT version suffix and publish to
starshipos-snapshots Nexus repo instead of starshipos-releases.
Push-to-master releases continue to use -<sha> suffix.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Runs api-docs (Doxygen → AsciiDoc), docs-latex (AsciiDoc → LaTeX via
asciidoctor), and math-companion (LaTeX → PDF) in a dedicated job
parallel to builds and Isabelle verification. Installs doxygen, Ruby +
asciidoctor-latex gem, and texlive. Uploads docs as a Gitea artifact
on every run regardless of pass/fail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Runs StarForth session (52 theories) in parallel with the board build
matrix. Caches the Isabelle2024 installation (~800MB) and the compiled
heaps keyed on proof/**/*.thy + ROOT, so only theory changes trigger a
full rebuild. Uploads the build log as an artifact on every run
(pass or fail) for audit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Builds all boards (qemu, pc, pi4, pi5, milkv) in parallel. Installs
cross-compilers (aarch64-linux-gnu, riscv64-linux-gnu) and clang-18
for the aarch64 loader. Packs ISO (amd64/aarch64) and GPT image (riscv64).
On master push, publishes to Nexus starshipos-releases using Maven
coordinates org.f18:kernel:<version>-<sha>:<board> and
org.f18:starforth:<version>-<sha>:<board>.
CROSS_COMPILE wired into StarForth Makefile via mk/boards.mk so
make T=pi4 picks up aarch64-linux-gnu-gcc automatically.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
T= now names a specific board (qemu, pc, pi4, pi5, milkv) rather than
an arch alias. mk/boards.mk is the single table: sets ARCH, BOARD, and
BOARD_NAME. Each Makefile applies board-specific compiler flags after its
arch block — pi5 gets Cortex-A76 tuning, pi4 gets Cortex-A72, qemu uses
portable x86-64 baseline instead of -march=native. Zynq-7020 is stubbed
in comments for future 32-bit ARM support. ARCH= override still works
for raw arch selection without a named board.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
T= is now shorthand for ARCH=, selecting the target board (raspi, amd64,
aarch64, riscv64). StarForth TARGET is locked to fastest — it's the only
build profile. Makefile.starkernel T= wired the same way before ARCH
normalization runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lets you type make T=fastest or make -f Makefile.starkernel ARCH=amd64 T=kernel
instead of the full TARGET= form. T= is resolved before the strip pass so it
behaves identically to TARGET= in all cases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix-doxygen-unicode.py protected the first argument of each
\doxynewunicodechar{...} from its replacements, then turned every
non-ASCII character left in the file -- the protected ones too -- into
"?" and wrote the file as ASCII. refman.tex's \doxynewunicodechar{⁻},
{²} and {³} became \doxynewunicodechar{?}, and newunicodechar stopped
the build: "ASCII character requested".
The "?" fallback now applies to the unprotected parts of each line
only, and the file is written as UTF-8.
make -C docs/formal doxygen, from clean, with doxygen 1.9.8: exit 0,
build/doxygen/StarForth-API-Reference.pdf, 3561 pages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
isabelle build -v -D proof/ with Isabelle2025-2 (installed by make init):
HOL-Library built (0:04:42), then the StarForth session's 52 theories,
every one in proof/ROOT (0:00:24); 0:05:24 in all, exit 0, nothing
FAILED. No sorry or oops in any proof (the words appear only in
comments) and quick_and_dirty is not set. The two explicit axioms are
both in StarForth_Transition.thy, the inventory StarForth_Correctness.thy
gives.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Neither is packaged. make ARCH=<arch> init now downloads both to
build/cache/downloads, checks each archive's SHA-256, unpacks it into
build/cache/tools (both kept by make clean) and links it into
/usr/local/bin:
- syft 1.52.0, the version sbom.spdx was made with (make sbom,
boot_image); sums from the release's checksums.txt;
- Isabelle2025-2, the version proof/COVERAGE.md names (isabelle build
-D proof/), from the release's own site (the /dist mirror answered
503); Isabelle publishes no sums, so these are of the archives as
downloaded on 2026-11-06.
An archive already there with the right sum is not downloaded again;
a download with the wrong sum is deleted and init stops. The host's
build is chosen by uname -m (amd64 or arm64).
Checked on Ubuntu 24.04 (x86_64): both fetched, checked and run (syft
1.52.0, Isabelle2025-2); a wrong sum is refused and deleted; isabelle
build -n -D proof/ finds the StarForth session.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
One ISA or several (ARCH=amd64,aarch64,riscv64, for the full
acceptance), on Debian/Ubuntu with apt-get, sudo when not root:
- common: the build, the disk-image tools (scripts/mkdiskimage.sh;
sfdisk is in fdisk), git-lfs for the logs and DoE CSVs, and the
documents -- docs/book/Makefile's own list, and pdflatex, doxygen and
graphviz for docs/formal;
- per ISA: its QEMU, its UEFI firmware at kernel/Makefile's paths, and
its compiler (aarch64's loader also needs clang and lld-link).
Then git lfs install --local, so a log or CSV committed from this
checkout goes into LFS (the 1003 plain files fixed in 027b144e came
from a checkout without it). Not installed: syft (make sbom), which is
not packaged.
Checked on Ubuntu 24.04: init for all three ISAs, then make docs and
make -C docs/formal vols build. make -C docs/formal doxygen fails in
LaTeX on "newunicodechar Error: ASCII character requested" with every
package present -- a separate fault, not a missing dependency.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
The acceptance runs of .claude/CLAUDE.md, one QEMU at a time, in order,
each with clean (scripts/qemu_session.py, QEMU_DISPLAY=none):
amd64 zuse 20261106-004933 PASS
aarch64 zuse 20261106-005153 PASS
riscv64 zuse 20261106-005530 PASS
amd64 stick_zuse 20261106-005712 PASS (--target qemu-stick-high)
Each: [zuse@Hera] ok>, `3 4 + .` -> 7 ok, PARITY:V4_POST tests=538
pass=538 fail=0, POST: PASSED. PARITY:V4_SYSTEM word_count=317
dict_hash=0xfec8c47cfc6f437f on all three architectures.
make -C v4 test-32: 39 test programs, 1868561 checks, 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
.gitattributes has routed logs/**/*.log, *.log and the DoE run CSVs
through LFS since the initial commit, and 3944 of them are pointers.
1003 were committed as plain files instead (from a checkout without
git-lfs), so every fresh clone showed them as modified. git add
--renormalize moves them to LFS like the rest. Content unchanged: each
pointer's oid is the sha256 of the file it replaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
- hosted (v4/tools/hosted.c): a line longer than the buffer is read to its
end and refused as too long. Before, fgets handed it over in 1025-byte
pieces and the last piece ran as a line of its own.
- bare metal (kernel/src/v4/sk_v4.c): the line editor takes 1024
characters, as the boot does, and a line typed past that is refused as
too long instead of being cut at 255 and run. V4_BOOT_LINE_TOO_LONG is
now reported at the prompt and while a line waits.
- engine (v4/src/exec.c): a store the node itself refuses (to "any port",
"which port", How or Have) left the opcode running on: !+ advanced A,
against node.h's FAULTS, and !p advanced P past the handler, into the
next fault kind's entry. A refused store now does nothing more; a store
that raises an error (D-18) still counts as made, but P stays the
handler's.
- test_port.c: both cases; they fail on the old exec.c (A 1017, P 901).
Engine-level tests (all v4/tests/test_*.c but test_host_*) pass at 32 and
64 bits; test_port also under ASan/UBSan. Not yet run: make -C v4 test,
test-32, hosted-check, and the three QEMU acceptance boots.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
Five tasks, each closed by full acceptance: the proxy Zuse (a stick's first boot mints its own;
genesis marker version 2), Artemis grown to fill the stick (metadata only), acceptance on a fresh
data stick, MINT-ZUSE onto a second stick (read back before the marker names her), and the fixed
screen whose only action is a replacement that kills the old stick.
R1 ruled (Captain Bob, 2026-10-29: "256 GiB is ruled"): Artemis grows to at most 256 GiB, not
STICK.md §5a's 2 TiB -- the block map costs two bytes of the 2 GiB kernel heap per 1 KiB block.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Captain Bob, 2026-10-29: "i want this a plug & play solution" -- "plug it in, it boots to the
prompt, no setup". STICK.md amended (§2, §3, §4, §6, new §6a, §7, §9, §10, §11), each change
saying what the text said before:
- A stick's first boot mints its own proxy Zuse (§6's genesis, minted at first boot, not at
build, so no two sticks share a key): full Zuse "until the real one is minted".
- MINT-ZUSE mints the real Zuse onto a second stick, after a typed YES, read back before the
genesis marker (version 2: the proxy's key and the real Zuse's) records her.
- With a real Zuse, the system stick alone gives a fixed screen whose only action is minting a
replacement ("the later"); a replacement kills the old stick "for good".
- Amends R2 ("only this system's stick is used") for the real Zuse stick, and supersedes "Zuse's
identity is on the same stick that boots". The open risk -- the system stick stays a master
key through the fallback -- is written down in §6a.
- §11: the proxy goes into increment 5; the real Zuse stick is a new increment 5a.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The SER5 stopped at the loader's "Loading kernel from ESP...": built -fno-pic -fno-pie with
ImageBase 0, the image carried ~9,000 32-bit absolute addresses, and the firmware loaded it above
2 GiB, where the sign-extended ones (R_X86_64_32S) point into unmapped memory -- a page fault in
debug_checkpoint() before [CKPT 001]. Reproduced on QEMU's pc machine at 3 GiB (#PF, CR2 =
FFFFFFFFBD316542, the right address sign-extended); q35 always loads it below 2 GiB, so no QEMU
boot ever showed it.
amd64 now builds -fpie with kernel/include/starkernel/pie_hidden.h force-included (#pragma GCC
visibility push(hidden)), so globals are RIP-relative and none is reached through a GOT -- the
2026-08-06 bug that put -fno-pic there. The link refuses any object carrying a 32-bit absolute or
GOT relocation (4,531 on the old objects, none now). test_runner.c's visibility("default") on
global_test_stats is kept for the -fPIC ISAs only. make -f kernel/Makefile ARCH=amd64
qemu-stick-high boots the PC stick on pc with 3 GiB and is part of acceptance (.claude/CLAUDE.md).
Captain Bob, 2026-10-29; FABRIC-3.md XLIV.
Verified: qemu-stick-high with Zuse's pair, ok> and 7 ok, RIP sampled inside .text at base
0xBD297000 (logs/20261029-070253); acceptance amd64 -070508, aarch64 -070715, riscv64 -071138,
PARITY:V4_POST tests=538 pass=538 fail=0, POST: PASSED, dict_hash=0xfec8c47cfc6f437f on all;
make -C v4 test-32, 39 suites, 0 failures. Not yet booted on the SER5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scripts/write_stick.sh refuses a device that is not a whole, removable USB disk, that holds the
running system, that is smaller than the image, or that has a mounted partition (it prints the
udisksctl lines); shows the stick and asks for its name typed back; writes with conv=fsync,
flushes, reads the stick back and compares it with the image byte for byte; powers it off. On
Windows/macOS it points to balenaEtcher or Rufus. Captain Bob, 2026-10-28, after a terminal line
break dropped dd's bs=4M conv=fsync on the first SER5 stick.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KernelArgs gains screen_boot; cmdline.c parses screen=boot (with or without --; any other value:
off). With it, the v4 boot keeps the console mirrored to the framebuffer after POST, with the TTF
font, and says 'Screen: the console stays on until login (screen=boot)'; login and logout work as
without it, and nothing can be typed without Zuse. Without it, unchanged. For the SER5, which has
no known serial port (ruled 2026-10-28). BRINGUP.md: the smoke test's stick and starforth.cfg.
Tests: screen_boot (new) failed on amd64 and aarch64 before, passes on all three ISAs after;
screen_dark_until_login, screen_dark_after_logout, zuse pass. Acceptance: amd64, aarch64, riscv64 to
[zuse@Hera] ok>, POST 538/538, dict_hash 0xfec8c47cfc6f437f; v4 suite and test-32 0 failures.
Plan: docs/v4.0.0/plans/2026-10-27-stick-4-one-disk.md, Task 5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sk_v4_identity.c: a USB drive is this system's stick if its GPT has both StarshipOS partitions and
it is the disk the loader booted from (BootDisk's DiskGUID), or, when the boot was not from a
stick, the first such disk while none is attached. Then: its Artemis partition must carry a good
artemis_sig ('Artemis: the stick's signature is bad -- not used' otherwise), is attached first --
the first disk slot -- ('Artemis: the stick's partition attached'), Zuse's key is read from its
genesis marker, and its identity partition is checked and attached as before. Any other drive,
raw or GPT: 'USB: a drive that is not this system's stick -- not used'. On a pull the identity
partition is detached, then Artemis. sk_v4_identity_boot / sk_v4_run take the loader's BootDisk.
kernel_main.c: no virtio Artemis on the v4 path. kernel/Makefile: ARTDISK= attaches no virtio disk
(every QEMU target); ARTDISK stays for system=v3.
STICK.md 4 amended as ruled (R2): on v4 only this system's stick is used; users' drives minted by
this system's Zuse come with the users design after INSTALL. BRINGUP.md: Secure Boot off on every
PC (ruled 2026-10-28), RDRAND in QEMU, the SER5 smoke-test stick, A4 not on v4.
Tests: new stick_artemis (x3, no virtio disk), stick_zuse, two_sticks (replaces datastick),
artemis_unsigned, raw_ident; changed stick_boot, gpt_zuse, gpt_hotplug, midpull (replug) -- all
failed before, pass after (two test defects found and fixed: the signature's offset, the 63-char
log cut). Regression 20/20. Acceptance: amd64, aarch64, riscv64 to [zuse@Hera] ok>, POST 538/538,
dict_hash 0xfec8c47cfc6f437f; v4 suite and test-32 0 failures.
Plan: docs/v4.0.0/plans/2026-10-27-stick-4-one-disk.md, Task 4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
uefi.h: the UEFI device path and Block I/O protocols, a typed LocateDevicePath, and BootDisk
{gpt, is_stick, disk_guid[16]} appended to BootInfo after args (boot_info_offsets.h unchanged).
The loader, before ExitBootServices, cuts its image's device path at the partition's HardDrive
node, locates the whole disk's Block I/O (whole path consumed, not a logical partition, 512-byte
blocks), reads it as 1 KiB blocks through a loader-side blkio adapter, and runs the kernel's own
gpt_read: is it a StarshipOS stick (identity and Artemis partitions), and its DiskGUID
(gpt_disk_guid, new). No HardDrive node (an ISO/CD boot), no GPT, or any failure: not a stick.
Monolithic builds only (the non-monolithic loader does not link gpt.c, and does not build today:
kernel/src/vm/vm_core.c -- reported, not fixed).
The kernel prints 'Boot disk: a StarshipOS stick' or '... not a StarshipOS stick', and on a stick
system=v3 gives 'System: v3 is not on this stick -- StarForth v4' and boots v4.
Tests: stick_v3 (new), stick_boot and zuse x3 failed on the new lines before, pass after; v3_keys
still boots v3 off a stick. Acceptance: amd64, aarch64, riscv64 to [zuse@Hera] ok>, POST 538/538,
dict_hash 0xfec8c47cfc6f437f; v4 suite and test-32 0 failures.
Plan: docs/v4.0.0/plans/2026-10-27-stick-4-one-disk.md, Task 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SPONSOR_PAGE, DEVLOG_01 and VIDEO_01 now live in studio/posts/drafts/, his gitignored workspace for
posts and video; git history keeps the committed versions (26c58879).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For Captain Bob to edit into his own voice: the sponsorship pitch and tiers, the first devlog
('Building an OS that keeps its own receipts'), and a 5-7 minute video script with an OBS setup.
Claims limited to what is true today: QEMU on three ISAs, the stick in progress, hardware next.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each of the 20 filed claims mapped to its support in the provisional as filed (final_provisional/,
43 pages): claims 1-19 solid or adequate, claim 20 thin. Findings: the K-statistic's definition
contradicts the specification's own data and figures; Solid vs Steady State Machine; claims 10-12
depend on a method as 'the system'; drawings need redoing to 37 CFR 1.84; result invariance and
the Jacquard detail are not disclosed. Recommendations for the non-provisional. Drafting aid, not
legal advice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sk_v4_block_chain calls rng_init() after pci_init, with v3's two lines ("entropy: ready" / "entropy:
not available (continuing without)"); genesis on a fresh stick (increment 5) needs it. amd64 QEMU
runs -cpu qemu64,+rdrand (qemu, qemu-stick, qemu-esp) and the amd64 qemu target drops virtio-rng,
so QEMU takes the PC's RDRAND path; aarch64 and riscv64 keep virtio-rng, their only backend.
qemu_session.py: mode entropy (rdrand on amd64, both targets; virtio-rng on aarch64/riscv64; then
entropy: ready). system=v3 sessions get Zuse's raw identity image: v3 never reads a GPT, so the
Zuse stick (Task 1) left v3_keys headless -- found here; CLAUDE.md says so for v3 boots.
Tests: entropy FAIL x4 before, PASS x4 after; v3_keys PASS (rng: backend = rdrand). Acceptance:
amd64, aarch64, riscv64 to [zuse@Hera] ok>, POST 538/538, dict_hash 0xfec8c47cfc6f437f; v4 suite
and test-32 0 failures.
Plan: docs/v4.0.0/plans/2026-10-27-stick-4-one-disk.md, Task 2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The outline for approval before drafting (target filing 2026-12-01..14, citing SSM-001): the method
that produces an operating system and its machine-checked proofs together, parameterised by
language; image and proofs bound by content hash; the self-tuning runtime proven not to change
results. Added 2026-10-28: explicit epistemic status of every claim -- proofs, the method of
construction, and the SDK's book capsule (6.9, and the claims' structure).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mkdiskimage.sh --starship-from IDENT ART lays a minted pair out as a StarshipOS stick: an identity
partition holding IDENT's bytes and an Artemis partition holding ART's, each exactly its file's
size (Artemis's signature and fence are placed from the volume's size). kernel/Makefile: a
zusestick target, made fresh for every boot, is ZUSEDISK's default (ZUSE_PAIR names the pair);
STICK_PAIR puts the pair in the PC stick. qemu_session.py's Zuse drive is the pair as a stick.
check_images.sh checks both forms byte for byte against the pair (60 PASS).
On today's kernel all 23 sessions pass on the Zuse stick, and acceptance: amd64, aarch64,
riscv64 to [zuse@Hera] ok>, POST 538/538, dict_hash 0xfec8c47cfc6f437f; v4 suite and test-32
0 failures. The plan gains Task 5, screen=boot (ruled 2026-10-28).
Plan: docs/v4.0.0/plans/2026-10-27-stick-4-one-disk.md, Task 1 (R1 as recommended).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of the stick's increment 3 (a4221d8b..c416c805), on Captain Bob's word:
- check_images.sh deletes both images before building and makes each build a
check: a failed build left last run's lithos-pc.img in place, and every stick
check passed against it.
- mkartemis takes --first-lba and --sectors as plain decimal numbers only:
"abc", "-2", "2048x" and the like formatted at LBA 0, over the GPT.
- mkartemis --format reopens the image read-only and reads the volume back:
blk_commit_format ignores its own write errors, so a header that never
landed was reported formatted. The header is read from the disk and judged
as attach judges it (magic, version 2, BAM size); blk_get_volume_meta gives
the in-memory geometry of a blank disk, magic included, so --check no longer
relies on it either.
check_images.sh keeps each case as a check (40, PASS). stick_boot and datastick
on amd64/aarch64/riscv64 PASS on the rebuilt tools.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
qemu-stick boots the amd64 stick image (build/boards/pc/lithos-pc.img,
copied per run) as a USB drive on q35, exactly as hardware would.
DATASTICK=1 adds the data stick to any qemu run as a second USB drive.
qemu_session.py gains --target and the stick_boot and datastick modes.
Checks: stick_boot (the stick's own identity partition attaches, headless
on a blank identity); datastick on amd64/aarch64/riscv64 (both drives
found, the data stick's 500 MiB identity attaches); the seven GPT modes,
the identity-gate and increment 1 sessions, emergency; the suite; three
acceptance boots to [zuse@Hera] ok> with POST 538/538 and
dict_hash=0xfec8c47cfc6f437f; test-32 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stick's increment 3, Task 1 (docs/v4.0.0/plans/2026-10-27-stick-3-images.md;
STICK.md 4). make boot_image TARGET=PC now writes the 2 GiB stick: ESP 64 MiB
(BOOTX64.EFI, startup.nsh, starforth.cfg), StarshipOS identity 500 MiB (zeros),
StarshipOS Artemis to the end. make -f kernel/Makefile ARCH=<arch> datastick
writes the 1.5 GiB data stick, identity and Artemis, fresh every time. Sizes in
kernel/Makefile; every partition on whole MiB.
tools/mkartemis formats and signs an Artemis partition at build with the
kernel's own code -- v3's block_subsystem.c (blk_subsys_confirm_format) and
artemis_sig.c (artemis_sig_genesis_stamp) -- through a blkio device over a byte
range of the image; --check reads one back the same way (read-only). disk_uuid
from getrandom(2): each image its own. mkdiskimage.sh gains --starship,
--mkartemis, --esp-mib; Milk-V and the Pi images are unchanged. The kernel is
not changed.
Red: scripts/check_images.sh FAIL (no datastick, the PC image one partition).
Green: 23/23. Mutation: --check on a range shifted by one block fails.
Accepted: suite EXIT 0; 133146, 133417, 133815, POST 538/538, dict_hash
0xfec8c47cfc6f437f; test-32, 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ruled (Captain Bob, 2026-10-27): the data stick is built and wired behind
DATASTICK=1, off by default; increment 5 turns it on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The increment 2 final review's minors 1-4 (Captain Bob, 2026-10-27: "fix 1-4"):
1. A protective MBR with no "EFI PART" header is GPT_BAD, not GPT_NONE: the
MBR says it is a GPT disk, and a GPT disk is never attached whole.
2. A disk whose block 0 cannot be read is GPT_EIO: "GPT: a USB drive could
not be read -- not used", nothing attached (it was read raw, attached
whole, and a raw Zuse drive behind it logged her in).
3. The entry array's LBA is checked against the disk's size directly.
4. gpt_bad_entries: the entry array changed, the header valid -- refused.
Harness modes gpt_no_header, gpt_read_error (blkdebug EIO on sector 0),
gpt_bad_entries. The plan carries the amendment.
Red (amd64): gpt_no_header 070335, gpt_read_error 070717 FAIL;
gpt_bad_entries 070048 PASS (existing check, now pinned). Green: every GPT
mode on amd64 071113-072933; gpt_zuse, gpt_read_error, gpt_no_header on
aarch64 073222-074047 and riscv64 074526-075535; the identity gate's and
increment 1's sessions 080036-082345, emergency 083130 (082635 was run
without EMERGENCY_CONSOLE_ENABLED=1 -- a harness invocation error).
Accepted: suite EXIT 0; 093121, 093352, 093750, POST 538/538, dict_hash
0xfec8c47cfc6f437f; test-32, 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kernel/Makefile wrote the boot arguments with printf '$(KERNEL_ARGS)\n', so
arguments starting with '-' were taken for an option -- "printf: Illegal
option --", the build stops; the Makefile's own documented example,
KERNEL_ARGS="--doe --log-level=info", hit it -- and a '%' in them would be a
conversion. Now printf '%s\n' '$(KERNEL_ARGS)', as the board images already
write theirs, at all four places (the amd64, aarch64 and riscv64 qemu
recipes, and qemu-esp).
Red: the stick's increment 2 sessions with KERNEL_ARGS=--log-level=info
failed in make. Green: amd64 203627, aarch64 203833, riscv64 204237 --
starforth.cfg holds "--log-level=info" and the boot shows INFO lines after
POST. Accepted: 214300, 214507, 214911; test-32 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stick, increment 2 (plan 2026-10-26-stick-2-gpt-reader; docs/v4.0.0/
STICK.md 3 and 4: GPT for boot media and installed disks). kernel/src/gpt.c:
a CRC-32; gpt_read(), which checks the protective MBR, the primary header and
the partition-entry array (both CRCs, the revision, the sizes, the geometry);
and a partition as a blkio device, refusing blocks past its end. The two
StarshipOS partition types: identity 23BEBFE1-4817-4CF3-A537-9069BF159788,
Artemis BCD7B586-1C8E-4EEF-86A3-273A8D8EE624.
The v4 drive path: a GPT disk is used only through its StarshipOS identity
partition, and that partition -- never the disk -- is given to the block
subsystem, in a raw identity drive's place; a GPT disk with no StarshipOS
partition, or a damaged table ("GPT: a USB drive has a damaged partition
table -- not used"), is not attached (Captain Bob's ruling on the plan); a
disk with no GPT is read raw, as always. Pulling the drive detaches the
partition and ends her session. Reads only.
Red (amd64): gpt_zuse 193158, gpt_hotplug 193804, gpt_foreign 194713,
gpt_bad_crc 194947. Green: 195409, 195627, 195854, 200136; gpt_zuse aarch64
200424, riscv64 200839 (the 64 MiB partition attached, 48724 user blocks,
not the 72 MiB disk); the identity gate's and increment 1's sessions,
201119-203403, all pass.
Accepted (with the KERNEL_ARGS fix that follows): suite EXIT 0; 214300,
214507, 214911, POST 538/538, dict_hash 0xfec8c47cfc6f437f; test-32, 39
modules, 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>