The `starlight` filter of ci-paths.yaml, and a job that runs `npm ci` and `npm run build` in starlight/. It is not
in the needs of `required` yet: the site has not been built by CI before.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The pages the unified macOS binaries and schemas make, as of this commit: the commands the site did not
have yet (consume, expel, pan and others) and the changed help of the rules. The Windows pages are not
regenerated: komorebic for Windows does not run on this host.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
`just docgen` takes no path now: it runs schemars-docgen from the tree (a member of the workspace) and
komorebic, writes the schema pages and the per-command pages into starlight/, and runs the script of the
site that makes the komorebic page of the platform from them, so nothing is left for `npm run build` to
generate. Only Windows and macOS have pages in the site.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
nix/docgen is nix/nixgen for the other tool: its own platform in workspace-src.nix (a stub in every other
platform, the templates it embeds kept), docgen-lint and docgen-test in the default check sets, and the
package in the dev shell, where `just docgen` runs it.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
clippy --fix and cargo fmt with the toolchain and rustfmt.toml of this repository, so that the clippy check
the flake runs with -D warnings passes.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
It is a development tool, like schemars-nixgen: the Cargo.lock and the manifest take its dependencies, and tera
takes the values of serde_json itself, so it stays off the workspace's serde_json_lenient.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The macOS job named 36 of the recorder's 731 tests by the module paths of its macOS sources. Its
tests are platform-neutral by module but worded in cfg!(target_os = "macos") branches (the options of a
recording, the keys of the viewer, the frames), so a Linux or Windows run takes the other side of
each and only a Mac takes this one, and a filter by name left most of that untested and would go stale
with every module. It runs the whole suite now: it compiles the same test binary the filter needed and
adds about 30 s of tests. In a depth-1 git checkout, as the runner has, all 731 pass (3 skip by design).
The filterset recorder-macos of tools/test-partition is gone with its use.
The test window and the agent of the e2e guests (class tool) have macOS sources (AppKit, the
accessibility API) that no other job compiles, and the tests of the test window's command line ran
nowhere. The job runs their tests and clippy.
With the os_sensitive step before it, every class of tools/test-partition that has macOS tests has a
run on a Mac: the macOS packages (macos-nextest), os_sensitive, the mixed ones (komorebi-client and
komorebi-bar in macos-nextest, the recorder whole) and tool.
Packages whose tests depend on the OS are in the class os_sensitive of
tools/test-partition.json, and a test of one can only pass on the host whose
behaviour it checks. windows-native-test runs them on Windows because the
Linux run cannot stand in for it. macos-hosted did not: macos-nextest builds
with -p of the macOS packages, so komorebic-core, whose docs_cli test
compares docs/macos/cli with what the macOS command line renders, ran on
no Mac in CI, and relied on the Linux run until the wording of Class
differed per platform (run 42311003287).
macos-hosted now runs `cargo nextest run` of the os_sensitive packages in the
native dev shell (92 tests; they pass on a Mac, checked locally). The cost is
macOS minutes on a public repository, which are free, and a compile of four
crates and their dependencies, a few minutes without a cache. docs/dev/ci.md
says so.
`komorebic-core::docs_cli every_macos_page_is_as_checked_in` failed in the linux-test run (1 of 1633 tests):
six pages of docs/macos/cli looked stale. ApplicationIdentifier::Class has three wordings through cfg_attr
(Class on Windows, "Accessibility subrole or role, such as AXStandardWindow" on macOS, "Role or subrole"
elsewhere) and the command line renders the wording of the host it is built for, so a Linux host cannot
render the pages as they are checked in, and the pages are right. The test skipped on Windows only, on the
belief that the linux run covered it, which stopped being true when macOS got its own wording.
The test file is built for a macOS host only now (#![cfg(target_os = "macos")]), so on another host there is
no test, where an early return would have been one that passes without having checked. Its remaining
guard, a missing docs/macos/cli, is an assertion: it was for the source tree of the Windows workspace, which
does not build the test any more.
The mirror checks were not off because the daemon tiles asymmetrically: the
agent read a stale work area (see the previous revision). With the displays
read fresh, layout_flip passes 62 of 62 without the marks, on five runs.
NSScreen keeps the visible frame it had when the process started: turning the
run loop does not refresh it, and the agent, which waits in accept, is up for
the whole run. The Dock of the guest shrinks its icons once the first test
windows are open (1280 points are not wide enough for the persistent apps and
the windows), its height going from 74 to 65 points, so the work area gains 9
points at the bottom, and the agent kept saying y 30, height 696 while a fresh
process said 705. The daemon reads the screens as it starts, so a shared check
that took the work area from the agent held the daemon to an area that was not
the system's, and the mirror checks of layout_flip were off by the difference.
The verb now runs the agent again with --print-displays, which prints what a
new process sees and exits, and answers in process only if that fails.
The test window now has a class (its accessibility subrole), and the state has it, so
manage_rules, state_fidelity and rules_class pass against a real guest: the three
known failures of the class difference and the skip of rules_class are removed. A run
with a mark on a check that passes reports it as a failure, so they could not stay.
placement stays skipped, for the initial_window_placement_rules the daemon does not have.
--class was accepted and ignored on macOS, so the scenarios that match a window by
a class could not run. The test window now sets its accessibility subrole to the
class (NSWindow setAccessibilitySubrole), and the host passes the app id of spawn as
--class.
The schema and the help of komorebic described the Class identifier as 'Role or
subrole'. It is the accessibility subrole of the window, or its role when it has no
subrole, and a rule matches either.
macOS has no window class, so a Class rule matched the role, which every ordinary
window shares (AXWindow) and which tells nothing: the subrole is what tells an
ordinary window (AXStandardWindow) from a dialog, a floating panel or a system
dialog. A Class rule already matched either of the two when the daemon decided to
manage, float or place a window on a workspace; the state showed neither as a
class, and an initial placement rule saw only the role.
The class of a window is now its subrole, or the role when it has none
(window::class_of). The state of a window has it as `details.class`, as the
state of a Windows or a KDE window does, so the tools that read the state read it
the same on every platform; a state from an older daemon without it still parses.
The rule a toggle of floating adds names the class, and ignore-rule matches a
window once when it matches by both role and subrole. A rule that names AXWindow
keeps matching, because rules take either.
enforce_workspace_rules moves a window between workspaces at the start of
an event but known_window_ids is only rebuilt at the end of process_event,
so it still said the window was on the focused workspace. A Show for the
application in the same event then passed the 'already associated with
another workspace' check, found the window in no container of the focused
workspace, and created a container for it there again: the window ended up
in the containers of both workspaces and in view on the one the rule sent
it from. Windows guards the same place by looking for the window in every
workspace before adding it; here the index is brought up to date when the
enforcement moved something.
closing needs the window that was opened last, which the Windows runner passes and this one did not,
so it never ran. maximizing uses `komorebic toggle-maximize`, which the macOS komorebic does not
have, and resize returns without a check when the platform has no pointer: both counted as passes of
their ten tiling checks. They are listed as skipped now, with the reason, as is the sweep of every
command, which is not wired to the macOS command set yet.
The two marks on the initial workspace rule go: that check fails on some runs and passes on others,
and a mark on a check that does both says it can go every other run.
The reasons of the two marks said the daemon fails to put a stack's windows away and has no fullscreen
detection. Both are how macOS is meant to work here: a stack is the focused window raised over the
others, and a fullscreen window is a Space of its own that the daemon does not tile. The checks stay
marked, because the shared scenarios ask what Windows and KDE do, but the reasons say that.
An initial workspace rule applied to a window leaves it on the first workspace as well as putting it
on the one the rule names: after it, the state has the window in the containers of both, and it is
in view at its tile (the daemon's log says it hid and restored it). It is the same on every run, in
the scenario and on its own, so the two checks about it are marked as a known failure of the macOS
daemon.
The marks are of one scenario each now: the check that says a window is put away while another workspace
is in view is a check that passes in rules_exe, and a mark on its words would have said so.
komorebic is done when a command is in the daemon's queue, not when it has run, and a scenario opens a
window right after giving a rule or a name: both are events of the same queue, and the window could be
first. The platform asks for `state` after every command that changes something, which the daemon
answers in the order it got things (the rules scenario failed a different check on each run before,
and its named-workspace checks pass three runs in three now).
The daemon watches its configuration file with FSEvents, and a file written in the first half second
after it answered is never noticed (0 s: not reloaded in 12 s; 0.5 s: reloaded after 2.6 s; later
ones after two or three seconds). A start waits a second for it, as nobody edits a file that fast.
config_reload goes from 6 of 8 checks to 8 of 8.
The first run of the scenarios against a real guest ended with 32 failing checks of 586. A window the
daemon puts away is parked with a sliver showing (fixed in the platform), and the rest are differences of
the macOS daemon, marked on the checks that are about them, with the reason:
- stacks: it stacks by raising the focused window over the others, and never puts the others away
- fullscreen: it has no fullscreen detection, and tiles a window over the whole display
- layout_flip: it tiles 10 px below the top of the work area and 12 px above its bottom
- class: a window has none, the daemon matches the role, which every test window shares
placement is skipped as a whole: the macOS daemon has no initial_window_placement_rules.
A step could be marked as a known failure of a port, which hides every failing check of it: too
coarse for a scenario in which one or two checks are about a difference of the port and the others
are not. RecordedChecks takes marks now: a part of the description of a check, and the reason. A
marked check that fails is recorded as a known failure, as a step is, and one that passes is a failure
of its own, so that a mark does not outlive the difference it was for. A port that gives no marks
is as it was.
The run of the runner's own subprocess calls says it does not check them.
macOS does not let a window go entirely off the screen, so the daemon hides one at the corner of
its display with one pixel of it showing (five for a window that scrolled away). The port
called a window hidden only when no pixel of it was on a display, so it said every window the
daemon had put away was in view. A window is put away now when no more than a sliver of it shows,
in either direction.
Against a real guest this takes workspaces, workspace_moves, monocle, lifecycle_hidden, rules_exe
and startup_rules from failing to passing (18, 18, 22, 23, 5 and 5 checks).
A README for e2e/platforms/tart_macos: what a run does, why the grants live in the golden image and
are inherited through Terminal, why the agent is a Rust program (the stock image has no developer
tools), and the limits (one display, no input, two guests per host, Apple hardware only, so not in
CI). docs/dev/ci.md and e2e-to-unit.md said macOS had no integration coverage; they now say where it
runs and what it cannot reach.
komorebi-e2e-macos builds the test window and the agent for macOS in a derivation of its own, on the
dependency artifacts of the macOS build, so that fullBuild (what users get) does not change. The
e2e-macos app, on aarch64-darwin, runs the scenarios of the shared core against the golden Tart image
with this checkout's daemon, as e2e-windows does for Windows: tart comes from nixpkgs, where its
licence makes it unfree, so only it is allowed, here. KOMOREBI_E2E_BINS runs another build, and
KOMOREBI_E2E_TART another tart.
build-golden.sh makes the golden Tart image from a vanilla one of Cirrus Labs: it provisions the
guest over SSH (provision.sh: the agent starts at login from a Terminal window, no state of earlier
runs is left, Terminal does not reopen old windows), stops for the one step that cannot be
scripted (a person allows Screen Recording and Accessibility for Terminal, once, and the grants live
in every clone), checks that the agent answers, and shuts the guest down from inside, so that
the last writes are on the disk the clones copy. build-bins.sh builds the programs under test for
the host and points the libiconv of the nix store at the system's, as the nix package does.
The check that runs the Python of the e2e guests that needs no guest (windows-e2e-tests, on
Linux) now also runs platforms/tart_macos/tests: the ignore rules, which windows count as hidden,
the paths a scenario may ask for, and that every scenario the macOS runner names exists in the core.
python -m platforms.tart_macos.run GOLDEN BIN_DIR OUT SCENARIO... gives each scenario a fresh
clone of the golden image, uploads the programs under test, starts the daemon and runs the shared
scenario, on the checks, step loop and result file the Windows runner uses (komorebi_vm.runner).
The scenarios a guest cannot run (a second display, a pointer, a lock screen, a window class) are
listed with the reason and skipped, not failed.
The unit tests of the port need no guest: the ignore rules, which windows count as hidden, the
paths a scenario may ask for, and that every scenario the runner names is a module of the core.
tiling (10 checks) and focus (17) pass against a real guest.
A clone of a golden Tart image is booted without a window and its agent (komorebi-e2e-agent, started
at login from the Terminal that holds the Accessibility and Screen Recording grants) is the only
thing the host talks to: no SSH, no password. MacosPlatform implements the Platform protocol
through it: the windows and displays are what the accessibility API says, the daemon is a program
the agent starts, a window the daemon put away is one off every display, and a screenshot is
screencapture.
A guest has one display and nothing here injects input, so has() says no to a pointer and to the
lock screen, and a second display is refused. The windows of the guest's own programs (the
Terminal, the desktop widgets of the image) are left to themselves by an ignore rule the platform
adds to every configuration.
The host side of the agent spoke a protocol that is the same for every platform, and lived in the
Windows port. Move it to komorebi_vm/agent.py, which the Windows module re-exports so that its
imports stay as they are, and give it the calls the protocol gained: spawn with an environment and
an output file, `status` of a spawned program and `send` to its standard input.
RecordedChecks (the checks a runner keeps for its result file), the step loop with its timings
and known failures, the commit under test and the step keyword helper have nothing to do with
Windows. Move them to komorebi_vm/runner.py, with the known-failure tables passed in, so that a
runner of another port uses them instead of importing a sibling port or copying them.
The Windows runner keeps its tables and the names it and its tests use. The unit tests of the core
and of the Windows runner pass unchanged (163), and ruff reports what it did before.
Move the macOS agent into komorebi-e2e-agent as macos.rs, answering the protocol of protocol.rs
with its own verbs (os_windows, displays, activate, minimize, close, move; a window is found by
its title), and remove the separate komorebi-macos-e2e crate that had copied the protocol. There
is one binary name and one port on every platform, so the host has one client and one description
of the protocol.
AppKit is for the main thread, so the macOS agent serves one connection at a time on it, where
the Windows one serves each on a thread. A spawned program on macOS gets a standard input that
stays open, as the test window leaves when its input closes. The crate is built for macOS and
Windows now and stubbed on Linux, as komorebi-testwin is.
The agent of the Windows guest speaks a line protocol (one JSON request, one JSON answer, raw bytes
after the line for put_file and get_file) that has nothing to do with Windows. Move it into
protocol.rs, with a trait for the verbs a platform adds, so that another platform answers the same
protocol instead of copying it, and the host has one client.
The Windows verbs (os_windows, displays, activate, minimize, close) and the code that reads them
from the session are moved to windows.rs, not changed; the agent still serves each connection
on a thread of its own. What the protocol gains for every platform: an environment and an output
file for a spawned program, a `status` of one, and a `send` to its standard input, which the
Windows agent does not use yet. The port is one for every platform, as the Windows one already was.
A spawned program now gets a pipe for its standard input that the agent keeps open: the test window
leaves when its input closes, which with /dev/null was at once. A new `send` verb writes a line to
it, which is how a scenario gives the window a command (fullscreen, title, resize).
The workspace keeps its list of running applications, and which one is active, up to date from
the main run loop, and the agent waits in accept: it listed the applications of the time it
started and never saw a window that opened later. It now lets the run loop turn before it lists
windows.
An AppKit window of a regular application, so that the daemon sees it as it sees any program: the
same options and standard input commands as the Win32 one (title, colour, size, minimum size,
fixed, late rename, fullscreen as a borderless window over its display, report with the frame in
points from the top left of the main display, close, exit). The main thread runs the event loop
in short turns and takes the lines the input thread queued; the program leaves when its window is
closed. A window class has no meaning on macOS, so --class is accepted and ignored.
The macOS source set now builds the crate; Linux still stubs it.
The test window of the e2e suite is a Win32 program whose command line (--title, --class,
--color, --size, --min-size, --fixed, --rename-to, --after) and standard input commands (title,
color, resize, report, close, exit) are the contract every scenario port relies on. Move what
knows no window system into cli.rs, with tests that run anywhere, and the Win32 window into
win32.rs, so that another platform can implement the same window against the same contract.
The Windows window itself is moved, not changed: it reads its options and its commands from
cli.rs now, and the colour is converted to a GDI one where it is used. A fullscreen command is
added to the shared set; on Windows it does what the WM_APP + 2 message does.
The Windows guest has komorebi-e2e-agent; this is its macOS counterpart, speaking the same
protocol (one JSON line per request, raw bytes after it for put_file and get_file) so that the
host client is the same. Beyond exec, spawn and file transfer it answers with the windows the
accessibility API gives (title, frame, focus, minimized) and the displays with their work areas,
and it can activate, minimize, close and move a window.
It has to be started by a program that holds the Accessibility and Screen Recording grants, so
that the daemon it spawns is attributed to that program.
The default dev shell exports CARGO_BUILD_TARGET=x86_64-pc-windows-msvc for the Windows cross
build. The native and the KDE checks run `cargo test` through `nix shell nixpkgs#gcc`, which is
not a dev shell and keeps the environment it was started from, so run from inside `nix develop`
they built their test programs for Windows and failed with "cannot execute binary file" (exit
126), the failure the recorder step of the macOS job had in CI.
Both lines now drop the variable. The macOS check names its target and the Windows check wants
the variable, so they stay as they were. With the variable exported, the native line fails with
126 before and passes (139, 8, 14, 20 and 16 tests) after.
The step ran `cargo nextest` in `nix develop`, whose default shell exports
CARGO_BUILD_TARGET=x86_64-pc-windows-msvc for the Windows cross build. On the
macOS runner that made cargo build the recorder's test executables for Windows,
and nextest then failed to list them:
for `komorebi-recorder::assert`, command `.../target/x86_64-pc-windows-msvc/debug/deps/assert-ce31ab528bf795df.exe --list --format terse`
exited with exit code 126 ... cannot execute binary file
Use `nix develop .#native`, the shell without the cross environment that exists
for exactly these `cargo -p komorebi-<platform>` commands. The schemas step
keeps the default shell: `just jsonschema` runs cargo through `env -u
CARGO_BUILD_TARGET`. docs/dev/ci.md notes the shell.
macos-14 was retired on 2 November 2026 and the runner label was no longer
supported, so macos-hosted was cancelled and failed required.
Only Apple silicon and the latest macOS are supported, and a standard hosted
runner is free on a public repository, so:
- macos-hosted runs on macos-latest
- it runs on a pull request that touches the macOS paths, without the label
ci:macos
- it needs only changes and lint, like windows-native-test, and no longer
waits for the KDE VM suites
- macos-selfhosted.yaml, its install-nix input, its path filter, the label
ci:macos-self and the variable MACOS_SELF_HOSTED are removed
A hosted runner of the ubuntu-24.04 pool is not promised nested virtualization, and
3 of the 16 suites of run 42182554717 failed the check of /dev/kvm. rerun-no-kvm.yaml
could not help: a workflow_run workflow runs only from the default branch, where the
file is not, and a run cannot rerun its own failed jobs while it is in progress.
The step "Enable KVM" of the nix action is now the only one that enables KVM
(enable_kvm of install-nix-action is off), runs before the disk and the install,
waits for udev to settle and polls /dev/kvm for 30 seconds instead of testing it
once, 42 ms after an asynchronous udevadm trigger, and prints what tells a missing
device from a rule that was not applied yet. With defer-no-kvm a host without KVM
is an output, not a failure.
_vm.yaml calls _vm-attempt.yaml up to three times: the suites that found no KVM are
listed through the artifacts of the run and run again on new machines, and the last
attempt fails them. vm-fast and vm-slow are calls of it. rerun-no-kvm.yaml is
removed.
A NAR of 460 MB was cut by the edge of the cache ("Stream error in the HTTP/2 framing layer") and the
resumed request failed the same way, so the job kwin-events failed before its VM test started. With
fallback = true Nix builds the derivation from source when a substitute cannot be downloaded: one dropped
connection costs minutes of compiling in that job, not the job. HTTP/2 is left at its default: nothing
shows that turning it off prevents the error.
ApplicationIdentifier::Class is described per platform ("Class" on
Windows, "Role or subrole" elsewhere), and the description is taken from
the host the test is built for. every_macos_page_is_as_checked_in renders
the pages of komorebic for macOS from the command line, so on the Windows
runner six of them (ignore-rule, manage-rule, workspace-rule,
named-workspace-rule, initial-workspace-rule and
initial-named-workspace-rule) came out with "- class: Class" and were
reported as stale, though the checked-in pages are right.
The pages are the same on the hosts that have the macOS wording, and the
linux test run checks them, so skip the test on Windows.
An unquoted ": " inside the description made action.yaml invalid YAML ("mapping values are not allowed in
this context"), so every job that uses the action would have failed at its first step.
nix flake check --no-build failed in the nix-eval job on the runner with "path ...-Cargo.lock is not
valid": crane's vendorCargoDeps runs pathExists on the lock at evaluation time, and `repoFile` is a
store path that builtins.path makes during evaluation. Nix 2.35 with an empty store, as on a fresh
runner, does not have it yet under --no-build; Lix, and a store that had seen the file, do.
The parsed lock now comes from the flake source (cargoLockParsed in nix/lib.nix), and the Windows guest
reads tools/test-partition.json the same way. The derivations are unchanged (same drv paths), so no
cache key moves. Reproduced and fixed with upstream Nix and an empty store:
nix shell nixpkgs#nixVersions.latest -c nix flake check --no-build --all-systems --store <empty dir>
The write token goes to cachix-action on a push (master and the temporary komomono
trigger, without naming either), a manual run and a schedule; a pull request, a fork
and the merge queue only read. The flake-lock update goes through the nix action too,
and the nixpkgs canary reads the cache but never pushes (push: "false" replaces
cache: "false").
docs(ci): the write rule, the read-only path and a checklist for the first push to
komomono.
The tools of stage 0 are the latest releases, taken from the flake, and the code is changed to satisfy
them, not the other way round: every run says which versions it had, and docs/dev/ci.md says how they
are kept current (the weekly lock update, and nix flake update rust-overlay or nixpkgs in between).
The pin was a week old: the hygiene shell had the nightly of 2026-10-27. The nightly of
2026-11-04 formats the whole tree unchanged. Every other tool of the shell was already the latest
release (actionlint 1.7.12, shellcheck 0.11.0, cargo-deny 0.20.2, ripgrep 15.2.0, jq 1.8.2, cargo 1.99.1).
The first stage ran shellcheck, rustfmt, cargo-deny and actionlint as the runner image, the
rust-toolchain rustup and two actions shipped them, and the runner's older shellcheck reported
SC2317 on a trap handler that the flake's does not. hygiene, fmt and deny now run every step in
`nix develop .#hygiene`, so CI and a local run use the same versions.
devShells.hygiene is the toolchain with the nightly rustfmt, cargo-deny, shellcheck, actionlint, jq,
ripgrep and git, without the Windows SDK, the VM tooling and the rest of the full shell, so that the
first stage sets up in seconds and a local `nix develop .#hygiene` runs what CI runs.
1.7.7 does not know the hosted Arm Windows runner and reported windows-11-arm as an unknown label.
1.7.12 is the latest release and the version nixpkgs gives `just lint`, so the hygiene job and a
local run now agree.
The ban (`just lint`, and now the hygiene job) came from the macOS and KDE repositories and was
never applied to the Windows code, so the unified tree had sixteen uses of the macro: seven in
the Windows daemon, six in komorebi-core (written during the unification), one in the KDE
backend and two in the recorder. Each becomes eyre::Report::msg, with format! where the message
has arguments.
The workspace members, the path dependencies, the include_str! and test
fixture paths, the recorder's indexed source keys, and the Nix source
filter and path literals follow the new layout. Cargo.lock is unchanged.
cargo deny list names a workspace crate by its path+file:// source, which is a path on the machine that
ran it (C:/Users/... before, /Users/... now). depgen strips it, and the file is regenerated for all three
platforms' crates.
It is reached only through font-loader, which komorebi-bar looks up system fonts with; it was
already in the lock before the recorder and schemars-nixgen merged.
nix/nixgen has the package and the clippy and nextest checks (in the default check sets), from a
"nixgen" platform of nix/workspace-src.nix that is the tool alone; it is a stub in every other
platform's source, so an edit of it rebuilds none of theirs.
It is a development tool: a bare cargo build leaves it out, publish is off, and no release
ships it. Its manifest uses the workspace dependencies it shares and keeps its own version.
nix/recorder holds the native packages and checks of macOS and Linux (the recorder and the
sources it indexes are the "recorder" platform of nix/workspace-src.nix), the Windows
build has it as one of its members, and the dev shell gets ffmpeg, resvg and GStreamer. The
flake inputs komorebi-mac and komorebi-windows are gone: the sources are in the tree.
The recorder is a member of the repository it indexes: each flavor is built from the
directory of its own daemon (komorebi-macos, komorebi-windows, komorebi-linux) and the shared
crates that log. The statements of the container, workspace and monitor moved into
komorebi-core, so the targets of the real log sample in the fixture are komorebi_core's.
KOMOREBI_SRC and KOMOREBI_COMMIT replace the three KOMOREBI_*_SRC variables, for a build
that is not in a checkout.
N1 is answered: macos-nextest runs in nix on a Mac (383 tests on the Mac Mini), the Windows
unit tests run in the Windows guest through nix run .#windows-nextest (964 tests, 964
passed, one run) with the check windows-nextest-build cross-compiling the 48 test
executables, and the neutral crates' tests run in linux-nextest (1532 tests). The remaining
open point is only whether the first CI also gets a hosted windows-latest cargo test job.
The R6 follow-up (the sponsor-only [FEAT] texts) and 2.2a are marked done.
Verified: documentation only; the numbers are from the agents' reports (win-nextest, and the
Mac Mini run of macos-nextest).
What: CUTOVER-PLAN.md records further owner decisions. R2: macOS is part of 0.2.0-dev; the owner tests it and releases 0.2.0 when ready; the macOS hand-check gates only the release, and the pre-release-later idea is dropped. R3: Starlight is the site for all docs, gh-pages is deprecated: new section 4.9 gives the retirement steps and what happens to mkdocs.yml (exclude_docs stays only while MkDocs builds anything) and the Windows docs source. R4: known failures do not block the dev-line landing. R5: published schema names agreed. R7: the owner handles the old macOS repository, so its banner/mirror/archive steps are removed (the KDE repository steps stay). R11 and every nixpkgs step are removed (no upstream package, the flake is the distribution). New section 4.8: the macOS nightly and its Homebrew formula must come from workflows of the joined repository, starting from docs/dev/old-ci/macos/workflows/*; not in the first CI; one nightly release for the whole repository. N1 (nextest) is marked in progress with the owner's two feasibility questions, not decided. Section 6 now lists what is truly open: the push (owner), the macOS hand-check, the self-hosted Windows runner, N1, and the release-time items.
How verified: sources read, nothing executed; the owner decisions are as relayed by the coordinator.