Skip to content

Rebuild vKore on libkore: Kore v0.40.0 machines and DagFS volumes - #53

Merged
micro-perceptron merged 7 commits into
mainfrom
ft/amazing-cray-qf1tpm
Nov 6, 2026
Merged

micro-perceptron merged 7 commits into
mainfrom
ft/amazing-cray-qf1tpm

Conversation

@SnowCheetos

@SnowCheetos SnowCheetos commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

vKore's first architecture was built around HostLink, a host-guest channel that never reached Kore's main: MicroPerceptron/kore#722, MicroPerceptron/kore#909 and MicroPerceptron/kore#933 were closed, and MicroPerceptron/kore#1015 is stale. A Kore release could not speak to that half of vKore, and the Kore crates it pinned by commit had drifted from any Kore that exists. This PR retires that half and rebuilds vKore on what Kore actually offers a host:

  • an ISO, and the QEMU topology Kore's own production gate boots;
  • the console markers Kore prints as it boots;
  • QMP;
  • DagFS volumes, through Kore's own engine, exported by libkore.

Kore reaches vKore through one dependency: kore-host from libkore (MicroPerceptron/libkore#31, pinned at 3aac3b5, which exports Kore's main at 7074bda2). Nothing of Kore is copied here.

What vKore does now

  • Machines (vkore machine create|run|changes|apply): boots an ISO on Kore's gate topology with the host's QEMU probed rather than assumed, follows the boot by Kore's own markers (kernel, services, shell, ready, degraded, failed), and stops it with the power button. With Kore's main from 7074bda2 (MicroPerceptron/kore#1475) the stop is graceful, 0.35 s after the press. Older Kore under QEMU never hears the button, so vKore ends QEMU after --grace.
  • Volumes (vkore volume DISK info|ls|tree|cat|get|put|rm|format|shots): a machine's disk, an image, or a block device. Reads, previews (from a file's head, never decoding pixels), exports and installs go through Kore's all-or-nothing publication. Exports never go through a symlink, never over a file unasked, and are published only once synced. The folder an export is sent to is created if it does not exist.
  • Screenshots: vKore creates pictures/screenshots before each boot, since Kore's capture app saves only into an existing folder. It lists and exports captures with their record (build, time, mode, region, uptime and any other kore: keys). Kore writes a capture seconds after PrintScreen and a stop does not wait for it, so the documented round trip waits 15 s.
  • The desktop (vkore-ui): Volumes and Machines, in-process, Iced over Axiom.
    • Shaping is confined to the bundled faces, so a host-installed JetBrains Mono can no longer blank the window.
    • Text from a guest or the host is escaped where a face cannot draw it, and controls, direction overrides and invisible characters are shown.
    • Starting a machine releases its disk from the browser and reopens it when the machine stops.
  • Removed: the HostLink endpoint and inference registry, the harness and its API, vkore-workspace, vkore-hostlink-ab, the launchers and gate scripts. The policy, package and add-on crates stay, with no guest path until a channel exists; MIGRATION.md says how one comes back (through Kore and libkore, never ahead of them).

Commits:

  • 5e39761: the rebuild.
  • 2d24e0f: docs (README, docs/compatibility.md, docs/desktop.md, MIGRATION.md, AGENTS.md).
  • 820d7fd: docs on why stops are graceful with the PM1 fix and were not before.
  • 82a035c: an export creates the folder it is sent to, once it has something to copy. shots reports refusals instead of taking them for an empty folder.
  • d8a8848: pin libkore 3aac3b5 (Kore main 7074bda2), verified on that commit's ISO, and the capture timing a graceful stop exposes.
  • 07e10f5: in the desktop, a hovered row no longer wears the selection's border, the volume root's breadcrumb has one slash, and counts agree with their nouns (also in the CLI).
  • ea6ab0d: README, the desktop on a physical Kore disk.

Verification

Linux x86_64 container, QEMU 8.2.2 TCG, at 07e10f5:

  • cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings and cargo test --workspace (119 tests) pass. The desktop's tests include headless page renders: no text refusals, and the shared kernels drawing a page pixel-identical to the scalar reference. The QMP client has tests for late replies, mid-line timeouts and line bounds.
  • The opt-in boot test passes on a production ISO built from Kore 7074bda2 and on a production v0.40.0 ISO.
  • The 7074bda2 ISO: vkore machine run boots to ready (19/19 services, 45/45 apps), presses PrintScreen, and stops gracefully. vkore volume @NAME shots --get copies the capture out with its record, byte-identical to the volume's copy. With --stop-after 5 or 7 the capture was lost; with 10 or 30 it was saved.
  • The v0.40.0 ISO: the same run to ready (44/44 apps), with the capture copied out. The stop ends QEMU after the grace period.
  • An older disk that v0.40.0 formatted, booted by the 7074bda2 ISO: ready, with both builds' captures on the volume.
  • A GPT disk on a loop device (Kore user and system partitions): an install through the partition node, and exports through the partition and whole-disk nodes byte-identical to the source. Nothing outside the user partition changed. With another partition on the same disk mounted, as on a dual-boot machine, writes go through the user partition's node. Naming a partition that does not hold the volume is refused, and the refusal names the one that does.
  • The desktop under Xvfb: browsed, previewed and saved a capture byte-identical, and started, followed and stopped the machine.

On a physical machine with Kore and Ubuntu on one NVMe disk, booted into Ubuntu (run by the maintainer): the desktop opened Kore's user volume through the disk's node. It previewed a 2880×1800 capture's record and saved it out.

Not verified

KVM or HVF acceleration, writing to a physical disk, macOS, AMD hosts.

Notes

  • The desktop depends on Axiom, which is not public yet (.cargo/config.toml fetches it with Git credentials). Every other crate builds from public sources.
  • Kore's graceful shutdown does not wait for a capture still being written, and Kore prints no console line when one is saved. So --screenshot cannot wait for the save; the docs give a measured wait instead. A console marker for a saved capture, in Kore, would let it wait exactly.
  • Reading a Kore disk from the host needs read access to the whole disk's node, and writing needs read-write on it and on the volume's partition. Today that means root, or ACLs on those nodes. Device access through udisks2 is a follow-up.
  • This supersedes the HostLink direction of the open Real Kore multi-chat, workspace authority, and runtime diagnostics #39.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ACHC7gzaAcosxJUPe73SWh

HostLink, the host-guest channel the first vKore was built around, never
reached Kore's main line (Kore #722, #909 and #933 closed; #1015 is
stale), so a Kore release could not speak to half of vKore, and the Kore
crates it pinned by commit had drifted from any Kore that exists. This
retires that half and rebuilds the host side on what Kore v0.40.0 offers:
an ISO, its production gate's machine topology, console markers, QMP, and
DagFS volumes, whose engine libkore now exports.

Kore reaches vKore through one dependency, `kore-host` from libkore
83d8347 (Kore ab6e7b15), the exported `kore-vol` procedure over Kore's own
filesystem engine. Nothing of Kore is copied here.

- vkore-volume (new): volumes from the host. A browser actor holds one
  mount; listings, bounded head reads for previews (a PNG's size and Kore's
  capture record precede its pixels, so none are decoded), exports that
  never follow a symlink or overwrite unasked and publish a synced file,
  installs and removals through Kore's all-or-nothing publication, and
  project staging and bounded write-back. One opener per disk per process.
- vkore-vm (rewritten): QEMU on Kore's gate topology, with the host's QEMU
  probed rather than assumed, firmware from QEMU's descriptors, the ISO's
  paging mode read through a bounded Joliet reader, QMP with command ids (a
  late reply is dropped, not taken for the next one, and a timeout inside a
  line loses nothing), and readiness from Kore's own console markers.
- vkored (rewritten): machines and their private state, boot sessions with
  JSON-lines transcripts, the screenshots folder Kore's capture app needs,
  and the `vkore` CLI (probe, iso, machine, volume). Configurations are
  validated when written and when read.
- vkore-ui (rewritten): Volumes and Machines, in-process. Shaping is
  confined to the bundled faces, so a host's own JetBrains Mono can no
  longer blank the window, and text from a guest or host is set through one
  guard that escapes what the face cannot draw, controls, direction
  overrides and invisible characters. Starting a machine releases its disk
  from the browser and reopens it when the machine stops. Render tests hold
  pages to no text refusals and to the scalar reference, pixel for pixel.
- Removed: the HostLink endpoint and inference registry, the harness and its
  API, vkore-workspace, vkore-hostlink-ab, the launchers and gate scripts.

Verified on a production Kore v0.40.0 ISO under QEMU 8.2.2 with TCG: boot
to ready, PrintScreen, stop, and the capture read off the volume with its
record, from the CLI, from the desktop under Xvfb, and by the opt-in host
test. Not run: KVM, HVF, macOS, physical hardware, block devices.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACHC7gzaAcosxJUPe73SWh
The README, desktop guide and vkored's README describe what vKore is now:
machines on Kore's gate topology, volumes through Kore's own engine, the
screenshot workflow end to end, and what is and is not verified.
docs/compatibility.md records the identity (libkore 83d8347, Kore ab6e7b15,
DagFS format 5, the v0.40.0 ISO's SHA-256, QEMU 8.2) and the guest contract
vKore relies on, with how to move the pin. MIGRATION.md explains the retired
HostLink half and how a channel comes back: through Kore and libkore, never
ahead of them. AGENTS.md holds the working rules. The policy, package and
add-on guides say they have no guest path until then.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACHC7gzaAcosxJUPe73SWh
vKore's docs said Kore v0.40.0 does not act on the ACPI power button under
QEMU. It does: the button leads into the same graceful power-off path
`pwctl shutdown` takes. What failed was the register access: Kore read and
wrote the PM1 status and enable registers a byte at a time, QEMU decodes
them only as 16-bit words, and the button is bit 8, so it was never armed
and a press was never seen. Kore 547af218 accesses them at their width; an
ISO built from it, booted by vKore, powers off 0.4 s after the press
(services asked to quiesce, the runtime torn down, ACPI S5), where before
the stop waited out its grace period and ended QEMU.

The compatibility record adds that ISO (SHA-256 7493248a...) and says what
the host can and cannot trigger: shutdown through the button, while reboot
and suspend remain `pwctl reboot` and `pwctl suspend` inside the guest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACHC7gzaAcosxJUPe73SWh
Copilot AI balanced review requested due to automatic review settings November 6, 2026 00:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

Copy link
Copy Markdown
Contributor Author

copilot-pull-request-reviewer, this PR's only check, failed without reviewing anything: its session ended with HTTP 402, "You have exceeded your monthly quota". That is the organization's Copilot review quota, not this change. The same error stopped the reviewer on MicroPerceptron/kore#1475 and MicroPerceptron/libkore#31. A re-run won't pass until the quota resets or is raised.

This repository has no CI workflows, so the gates were run locally on this branch: cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace, and the opt-in boot test with a real Kore ISO. Adding a workflow that runs those on every PR would be a separate change. The desktop's Axiom dependency is not public yet, so that workflow would need a credential for it, or would have to build without vkore-ui.


Generated by Claude Code

…hing to copy

## Why

`vkore volume @name shots --get ~/Pictures/kore`, as the README gives it,
failed on a host without that folder: the export opened its destination and
met `No such file or directory`, and `get` did the same. With no captures,
`shots --get` instead said it had copied none into a folder that did not
exist. And `shots` took any refusal for an empty folder, so a volume it could
not read looked like one without screenshots, and with `--json` it printed
prose.

## What

- `Browser::export` reads its source first and then creates its destination,
  with any missing parents, as `mkdir -p` would: a path that names nothing
  leaves the host as it was. What the export writes below the destination
  still never follows a link. The desktop's Save goes through the same call,
  so a folder typed into its field is created too.
- `Error::is_not_found` names the engine's not-found refusal; the project
  collector uses it instead of matching the engine's variant itself.
- `shots`: a home not created yet, or one without the folder, holds no
  captures; any other refusal is reported as it is. With nothing to list it
  says so (`[]` with `--json`) and creates no folder.

## Verification

- `cargo fmt --check`; `cargo clippy -D warnings` and `cargo test` for
  `vkore-volume` and `vkored`, on this commit alone. A new test: a missing
  source creates nothing, a missing nested destination is created, and a file
  where the destination should be is refused and kept.
- By hand, through the release CLI on a machine's disk: `shots --get` into a
  missing nested folder, `get` into a missing folder, `get` of a missing path
  (refused, nothing created), and an empty home (no folder created, `[]` with
  `--json`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACHC7gzaAcosxJUPe73SWh
## Why

MicroPerceptron/kore#1475 is merged, by rebase: the Kore commits vKore named
(`ab6e7b15` for the engine, `547af218` for the power button) are `9d616ce0` and
`7074bda2` on Kore's main, and MicroPerceptron/libkore#31 now exports its
native tree at `7074bda2` (libkore `3aac3b5`). vKore's one compatibility
identity moves with it, and its docs name commits Kore's main carries.

## What

- `Cargo.toml`: `kore-host` at libkore
  `3aac3b5ce4870421581ffa9b8abc0837c63d2c41`. `Cargo.lock` moves the 16 libkore
  packages and no other package; Cargo re-resolves six Windows-only edges onto
  the `windows-sys` 0.59 already in the lock.
- `docs/compatibility.md`: the identity (libkore `3aac3b5`, Kore `7074bda2`,
  and the `7074bda2` ISO's SHA-256 beside v0.40.0's); the PM1 fix by its main
  commit; what a stop means for a capture.
- A capture and a graceful stop. Kore writes a capture seconds after
  PrintScreen (seven to ten under TCG here), and its shutdown does not wait
  for one still being written. v0.40.0 never hears the power button, so a stop
  gave the capture `--stop-after` plus the 10 s grace; a Kore that hears it
  powers off 0.35 s after the press, and `--stop-after 5` lost the capture.
  The README's round trip now waits 15 s, the compatibility and desktop docs
  say why, and so does `--screenshot`'s long help.
- README: what is verified, against both ISOs. Block devices leave the list of
  what is not: a GPT disk on a loop device has been used through vKore.

## Verification

Linux x86_64 container, QEMU 8.2.2 TCG, with this pin:
- `cargo fmt --check`, `cargo clippy --workspace --all-targets -D warnings`,
  `cargo test --workspace` (117 passed).
- The opt-in boot test (`vkore-vm --test host`) on the `7074bda2` ISO and on
  the v0.40.0 ISO: 3 passed each.
- The `7074bda2` ISO (SHA-256 `b085e919…`), a fresh machine: ready (19/19
  services, 45/45 apps, homes 1/1), PrintScreen, a graceful stop 0.35 s after
  the press. With `--stop-after` 5 or 7 the capture was lost; with 10 or 30 it
  was saved. `shots --get` copies it out with its record (build
  `7074bda28c41`), byte-identical to `volume cat`.
- The v0.40.0 ISO, a fresh machine: ready (19/19, 44/44, 1/1), PrintScreen,
  the stop forced after the 10 s grace, the capture copied out.
- A disk v0.40.0 formatted (and later Kore wrote), booted by the `7074bda2`
  ISO: vKore flags the changed ISO, Kore reaches ready and seeds its new app
  (45/45), and the volume holds both builds' captures.
- A GPT disk on a loop device: a device format refused, an install through the
  partition node, exports through the partition and whole-disk nodes identical
  to the source, nothing outside the user partition changed.
- The desktop under Xvfb: the disk opened on its screenshots, a capture
  previewed with its record and saved byte-identical, and the machine started
  headless, followed to ready and stopped gracefully in 0.3 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACHC7gzaAcosxJUPe73SWh
## Why

The desktop on a physical machine, reading Kore's NVMe from Ubuntu, showed
a capture's record in the preview while a different row wore the
selection's magenta border: the selected capture had scrolled out of view,
and the row under the pointer had the border too. `widgets::Button::Row`
documents that only the selected row carries it; hover gave it one as well.

The same screenshot shows two smaller faults:
- The volume root's breadcrumb read `/ / work`. Its own crumb is `/`, and a
  separator went before every component, the first one included.
- Counts did not agree with their nouns: "saved … (1 files, …)", and in the
  CLI "1 directories".

## What

- A hovered row is tinted only. The magenta border is the selection's alone.
- The volume root's crumbs read `/ work / face-0`; a home's still read
  `~0 / pictures`.
- Each view has one `count` helper ("1 file", "2 files"). It is used by the
  desktop's save, import and staging lines, and by the CLI's `get`, `put`,
  `shots --get`, `machine apply` and staging lines.

## Verification

- `cargo fmt --check`, `cargo clippy --workspace --all-targets
  -D warnings` and `cargo test --workspace` (119 passed). New tests: a hovered
  row never passes for the selected one, and a count agrees with its noun.
- Under Xvfb, on a machine's disk: the volume root walked to
  `work/face-0/pictures`. With one row selected and another hovered, the
  border is on the selection only and the hovered row is tinted. Save reports
  "1 file, 33151 bytes".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACHC7gzaAcosxJUPe73SWh
On a physical machine with Kore and Ubuntu on one NVMe disk, booted into
Ubuntu, the desktop opened Kore's user volume through the disk's node. It
previewed a 2880×1800 capture's record (125 % density) and saved it out:
the first physical disk vKore has read. Writing to one is still unverified,
and the list of what is not verified now says so instead of "physical
hardware".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACHC7gzaAcosxJUPe73SWh
micro-perceptron added a commit to MicroPerceptron/libkore that referenced this pull request Nov 6, 2026
…engine (#31)

Host programs (vKore first) need to read and write Kore's DagFS volumes:
a machine's disk image, or a Kore disk attached to Linux. This gives
them Kore's own procedure and engine instead of a second implementation
of the format.

## Changes

- **`crates/host` (`kore-host`)** is the host-side facade.
`kore_host::volume` re-exports the exported `kore-vol` library
(`format`, `put`, `rm`, `read` and its `Mount`, the bounds,
`FORMAT_VERSION`, `VolError::is_in_use`) and adds no behaviour of its
own. It is `#[forbid(unsafe_code)]`. `AGENTS.md` records its rule: no
second locate, recover or commit path, no host-side format writer, no
parsing of volume bytes outside the engine. Behaviour changes go to
Kore's `tools/kore-vol` and arrive through `tools/sync-native.py`.
- **`native/`** is re-exported byte for byte at Kore `main`
`7074bda28c416ffe34562857ee43cbc883482782`. That commit carries
MicroPerceptron/kore#1475 (merged by rebase): `tools/kore-vol` as a
library whose mount releases every engine handle it opens.
`tools/kore-vol` is a new owner root. Following its path dependencies
adds the filesystem service closure it drives (`kore-svc-dagfs`,
`kore-svc-block`, `kore-svc-device`, `kore-svc-mm`, `kore-svc-swap`,
`kore-nvme`, `kore-svc-extract-worker-c`), for 26 packages and 382 exact
files. Publishing that closure was an explicit decision: the alternative
is a second DagFS implementation. Eleven of main's commits since v0.40.0
(`e5e0b96a`) reach the closure; `docs/provenance.md` lists them. The
DagFS on-disk format is unchanged (version 5).
- **Advisories.** kore-wasi's Wasmtime requirements move to 48.0.8. The
root `Cargo.lock` takes Wasmtime/Cranelift/Pulley 48.0.8 and zstd
0.13.4, zstd-safe 7.4.0 and zstd-sys 2.1.2. That clears nine RUSTSEC
vulnerabilities and ten unsoundness notices, which fail the audit on
every branch cut from `alpha`. Nothing else in either lock moves.
- `Makefile` runs the exported `kore-vol` suites in `test`, formats
`kore-host`, and keeps it out of Miri. `README.md`,
`docs/integration.md` and `docs/provenance.md` describe the facade and
the export.

Commits:
- `74524f9`: the facade, and the export with its volume closure.
- `83d8347`: re-export at MicroPerceptron/kore#1475's `ab6e7b15`, where
a mount releases every engine handle on every path. Before it, a
long-lived reader could exhaust its session's 32 handles.
- `7033ba6`: Wasmtime 48.0.8 and the zstd family, past the advisories.
- `3aac3b5`: re-export at Kore `main` `7074bda2`, once
MicroPerceptron/kore#1475 landed.

## Verification

CI is green at `3aac3b5`: host (including `zig fmt`, `test-foreign` and
`bindings-check`), the three targets, Miri, Advisories and Lockfile
currency.

`docs/provenance.md` records the local set. Local runs, with the pinned
nightly:
- **`3aac3b5`:**
- Tests: the workspace (every feature except `test-foreign`), the native
`kore-rt`/`kore-dagfs` suites, the exported `kore-vol` suites (1 unit, 9
CLI, 6 library) and its loop-device suite as root (4), `kore-host`'s
volume tests, and the tool tests.
- Checks: the no-default-feature check, Clippy and documentation with
warnings denied, `cargo fmt --check`, the three Kore user-target checks
for `kore-std`/`kore-ffi`/`kore-entry`, `check-alloc-symbols`,
`check-entry`, Miri, the owner graph, the native drift check and the
local-composition fixture.
- Bindings: cbindgen regenerates `kore.h` byte-identical, and the C
consumers compile for all three ISAs.
- **`7033ba6`:** `cargo audit --deny warnings` exits 0 on both
lockfiles; on the previous root lock it reports the 19 findings. Both
lockfiles resolve `--locked`, and kore-wasi's tests pass.

The export has run end to end in vKore at `3aac3b5`
(MicroPerceptron/vkore#53, under QEMU 8.2.2 TCG):
- A production ISO built from Kore `7074bda2`, and a production v0.40.0
ISO, each booted to ready. vKore read off the volume a screenshot the
guest saved.
- A disk v0.40.0 formatted was booted by the `7074bda2` ISO, and its
volume read back with both builds' captures.
- A GPT disk on a loop device took an install through its Kore user
partition. It was read back through both the whole-disk and partition
nodes, with nothing outside the partition touched.

## Not verified

Physical hardware.

## Notes

- The open HostLink PR (#22) predates this
direction. HostLink never reached Kore's `main`; a host-guest channel
would come through this same export path once Kore has one.

---
🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01ACHC7gzaAcosxJUPe73SWh
@micro-perceptron
micro-perceptron merged commit 2edeaad into main Nov 6, 2026
@micro-perceptron
micro-perceptron deleted the ft/amazing-cray-qf1tpm branch November 6, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants