Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ spin-machine attach --qmp /tmp/q.sock --target 0 --disk disk.raw # sda, in the
spin-machine detach --qmp /tmp/q.sock --target 0
```

`detach` returns when QEMU reports the device free, but the guest notices the
ejection asynchronously: a check that greps for the node inside the guest runs
immediately after it can still see it, and saw it gone seconds later (measured
2026-10-03). Leave the guest a moment before treating a visible node as a
hot-unplug failure.

A one-off check needs no socket and no QMP: the shell's console is stdin/stdout, so
a script on stdin is what the guest runs, and `poweroff -f` ends the boot. `--init
/bin/sh` runs the script as PID 1 with nothing mounted, so it mounts `/proc` and
Expand All @@ -204,7 +210,9 @@ printf '\n\n\n\n\n\n\n\n\n\nmount -t proc proc /proc\ncat /proc/cpuinfo | head -
The leading blank lines are load-bearing: the guest's shell is not reading its console
when QEMU starts feeding it, so the first bytes of the first line are lost, and a
leading `sleep` would be the thing eaten — `mount` arrived as `unt` and `sleep` as
`ep` before the blanks absorbed it.
`ep` before the blanks absorbed it. How far the window reaches is host timing, not a
line count, so keep the number of blanks generous rather than tuning it; a blank
costs only a prompt.

## Taskfiles

Expand Down
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,13 @@ One tarball:

`LICENSE` and `NOTICE` sit at the root of the tarball.

`task build` writes that same tree into `_output/`, byte for byte the layout above, and
`machine.OpenRelease` reads either. `_output/bin/` holds one thing more: `spin-machine`,
`task build` writes that same tree into `_output/`, and `machine.OpenRelease` reads
either. What a release has beyond a build directory is what `hack/release` creates or
copies when it names one: `machine.env` and `SOURCES` it writes, and the QEMU and qboot
patches under `qemu/` it takes from this repository, not from the build. A tree without
a manifest is still a release for every purpose except being named — the fingerprint
decides whether checkpoints resume, and it is computed from the files, not from
`machine.env`. `_output/bin/` holds one thing more: `spin-machine`,
which `task tools` builds for working in this repository and `hack/release` does not ship —
a release is the machine, not the tool that boots it. There is one layout: nothing rearranges
the files on the way out of a build, into a tarball or into a consumer. Let the three differ
Expand Down Expand Up @@ -85,8 +90,10 @@ printf '\n\n\n\n\n\n\n\n\n\nmount -t proc proc /proc\necho hello from $(uname -r
so the script mounts `/proc` itself — `poweroff` refuses without it. The leading blank
lines are load-bearing: the guest's shell is not reading its console when QEMU starts
feeding it, so the first bytes of the first line are lost, and the blanks absorb that
instead of the first real command. Nothing touches the base image — without `--disk`,
QEMU boots it under a throwaway overlay (`-snapshot`).
instead of the first real command. How far that window reaches is host timing, not a
line count — a quiet host may lose nothing — so treat the number of blanks as
insurance, not a figure to trim: a blank costs one prompt. Nothing touches the base
image — without `--disk`, QEMU boots it under a throwaway overlay (`-snapshot`).

Read the output by grepping a marker, since the guest's prompt and the kernel's boot
chatter share stdout: `| grep -a MARKER`. The exit status is QEMU's, so a script that
Expand Down