What: CUTOVER-PLAN.md follows two owner decisions. R6: one sponsor-only [FEAT] policy and one licence apply to all three platforms; section 2.2a is the concrete list of texts to rewrite (feature-check.yaml message, ISSUE_TEMPLATE feature_request, bug_report and config, README and docs index sponsorship sections, the macOS README paragraph about a private repository, licence consistency), found with git grep. R5: no root schema*.json copies and no freshness test; section 2.2b states the consequence (the old master/ raw URLs, including the one komorebic quickstart wrote into users' applications.json, stop resolving), the repository tasks, and the wording for the README and the release notes. The per-platform published file names stay an open release question with a recommendation. How verified: sources read, nothing executed; the lists come from git grep on the tip 59b01fdb. Earlier revisions are not rewritten.
94 KiB
The plan to land the consolidated repository and release 0.2.0
Status: a PLAN, written 2026-11-01 by the agent merge-plan. Nothing in it has been executed. Sources were
read, nothing was run except read-only commands: jj log/jj file show/jj file annotate, git log/git grep/
git blame/git show on the local clone, gh repo view and gh api GET calls, gh issue/pr/release/workflow list,
and one curl -I (a HEAD request to a public schema URL, section 2). No branch, tag, issue, release, secret or setting was
changed, and no file outside this document was written.
Everything here is tagged with where it was found (a file and line, or the command) or marked (inferred) when it
is reasoning rather than something read. (unknown) means it could not be found from here. The cutover
stack read is wip-cutover-docs (2185556efba6, 2185556efba61c0185dc2154010bec9d37383b4d: wip-main plus the renames,
version 0.2.0, one deny/justfile/rustfmt, and the docs paths). The one root flake (agent flake-one, bookmark
wip-cutover-flake) had NOT landed when this was written (jj log shows the bookmark still on 6357bc65, the first
revisions on top of it being wip), so the flake outputs are named by placeholders: FLAKE_WINDOWS_PKGS,
FLAKE_LINUX_PKGS, FLAKE_MACOS_PKGS (the packages komorebi/komorebic/komorebi-bar of each platform),
FLAKE_CHECKS_<platform> (the nix checks), FLAKE_VM_TIERS (the KDE VM tiers as JSON) and
FLAKE_E2E_WINDOWS (the Windows e2e app, nix run .#e2e-windows today, flake.nix:648 at this revision).
Replace them from wip-cutover-flake when it lands; everything else stands.
The token. The origin URL of ~/komorebi-for-mac embeds a GitHub token (seen in git remote -v; not copied here). Rotate it
now, whatever else is decided: anything that has read that clone's config, or this machine's shell history, has it.
The same URL form is used in docs/dev/old-ci/macos/workflows/nix.yaml only as secrets.GH_USER_API_TOKEN, which is a
secret name, not a value.
Owner decisions taken after the first version of this plan (2026-11-01, relayed by the coordinator; they override the first version where they differ):
- No private sponsors repository. There will be no private mirror (
KomoCorp/komorebior any other) and no sponsors-only early access. The history of the old private repositories becomes public with the push, once the owner confirms the push itself (step S4). R1 is therefore answered as to the mirror; the confirmation of the push stays a gate. - Schemas are per-platform files in the repository. Done:
schemas/{windows,linux,macos}/{schema.json,schema.asc.json,schema.bar.json}(linux has no bar schema). R5 is decided (no root copies either: owner, later message); only the published file names stay open. - 0.2.0 is not published now. The workspace version is
0.2.0-dev(as told; the first version of this plan read0.2.0atCargo.toml:61of2185556efba6; re-read it on the final tip). The landing of the line is the beginning of the 0.2.0-dev line:komomonotomastercarrying0.2.0-dev, no tag, no release artefacts, CI on. The later release of 0.2.0 (a revision that sets0.2.0, tagv0.2.0, artefacts, announcement) is a separate step with its own gates. The macOS hand-check gates the release, not the dev-line landing. - One sponsor-only
[FEAT]policy and one licence for all three platforms (R6), and no rootschema*.jsoncopies (R5). The texts that describe the policy must be rewritten for one public project with no private tier (task list 2.2a); the old Windowsmaster/schema URLs stop resolving (2.2b: README and release-notes wording). The published per-platform schema file names stay open until the release. Sections 4 and 5 and the checklists are split accordingly: DEV-LINE LANDING (steps L0 to L6) and RELEASE (steps E1 to E8). Where the text below says "S4/S5/S7/S8" the new names are: S4 = L3, S5 = L4, S6 = L5, S7 = E3, S8 = E5.
0. What is where today (the facts the rest depends on)
| Fact | Source |
|---|---|
LGUG2Z/komorebi (Windows): public, default branch master (72aa4c97), 15,331 stars, 376 forks, 755 issues ever (89 open), 858 PRs ever (27 open: 19 not by dependabot, 8 dependabot), no branch protection, no rulesets, GitHub Pages from branch gh-pages (https://lgug2z.github.io/komorebi/), 30 branches |
gh repo view, gh issue list --state open/all, gh pr list, gh api repos/LGUG2Z/komorebi/branches/master/protection (404 "disabled"), .../rulesets (0), .../pages |
LGUG2Z/komorebi-for-kde: private, default master = 7d19fd40, 0 stars, 0 forks, 1 open issue (the auto-opened "Canary: a check fails against the tip of nixpkgs-unstable", #6), 5 PRs ever (0 open), 0 releases, 0 tags, workflows ci, rerun-no-kvm, update-flake-lock |
gh api repos/.../komorebi-for-kde (visibility: private), gh issue list, gh release list (empty), git tag (0) |
LGUG2Z/komorebi-for-mac: public, default master = 2cd5884f, issues disabled, 261 stars, 4 forks, 0 PRs ever, releases v0.1.0-prerelease, v0.1.0, v0.1.1 (v0.1.1 Latest, 2026-05-03), homepage https://komorebi.lgug2z.com; the merged macOS history is the branch ash-squashem = 9a58e511, 41 commits ahead of that master |
gh repo view, gh release list, git rev-list --count master..ash-squashem in ~/komorebi-for-mac, gh api .../branches |
KomoCorp/komorebi-for-mac exists and is private (visible to gh as .private == true); it is where the macOS CI ran and where the macOS development happened (docs/macos/README.md:43-47). It is retired by the owner's decision: nothing replaces it, and its README text must go (class C in 2.3) |
gh api repos/KomoCorp/komorebi-for-mac --jq .private; docs/macos/README.md:43-47 |
The macOS CI runs only in that private repo on a self-hosted runner; in the public repo every run is skipped (the job guard is github.repository == 'KomoCorp/komorebi-for-mac') |
docs/dev/old-ci/macos/workflows/nix.yaml:21-22; gh api .../komorebi-for-mac/actions/runs (all skipped) |
komomono is already on GitHub: LGUG2Z/komorebi branch komomono = ff3711dc (committed 2026-10-31T01:59Z), 85 commits ahead of master; next = 72aa4c97 (= master) |
gh api repos/LGUG2Z/komorebi/branches/komomono, git -C ~/komorebi log --oneline master..komomono (85), git merge-base master komomono (= 72aa4c97) |
The local line: wip-main = 21cf0d73 (landed consolidation), komomono@source = ff3711dc is its ancestor, jj log -r 'wip-main..komomono@source' is empty and komomono@source..wip-main has 1110 revisions (master@source..wip-main: 1195). The stack wip-main..wip-cutover-docs has 24 revisions (jj log -r wip-main..wip-cutover-docs) |
jj log revset counts |
Superseded: the master plan's "local 3127741c vs komomono@origin 989a2d4a (reconcile first)" no longer applies: both sides are ff3711dc and the local line is a pure descendant |
plan generic-percolating-matsumoto.md (tips read 2026-10-30) vs the commands above |
History is whole: the old tips (KDE 7d19fd40, macOS 9a58e511, Windows 72aa4c97) are ancestors; commit counts preserved (KDE 254, macOS 304) |
progress log (entry of the A2 merge: "old tips resolve and are ancestors", "commit counts preserved (KDE 254, macOS 304)"); git cat-file/merge-base --is-ancestor of the macOS tags below |
Tags: Windows v0.1.0..v0.1.41 plus nightly (43 tags, all lightweight: git for-each-ref reports object type commit for each); macOS v0.1.0-prerelease, v0.1.0, v0.1.1, nightly; KDE none. The macOS names v0.1.0 and v0.1.1 COLLIDE with Windows tags of the same names on different commits; the work clone has only the 43 Windows tags (macOS tags were not imported) but the macOS tag commits (64341e29, ebbd9eee, 0cc4ca7f) are ancestors of the cutover stack |
git tag in each clone; git merge-base --is-ancestor |
| Windows 0.1.41 downloads (a proxy for users, not a user count): x86_64 msi 47,170, x86_64 zip 12,074, aarch64 msi 2,909, aarch64 zip 1,727. macOS v0.1.1 zip: 851. Active user count: (unknown) | gh api repos/LGUG2Z/komorebi/releases/latest, .../komorebi-for-mac/releases/latest |
Distribution channels of Windows: Scoop Extras manifest (checkver: github, autoupdate URLs .../releases/download/v$version/komorebi-$version-{x86_64,aarch64}-pc-windows-msvc.zip, hash from $baseurl/checksums.txt), WinGet LGUG2Z.komorebi (workflow job winget, secret WINGET_TOKEN), MSI (wix), cargo install --path komorebi-daemon --locked from a clone (docs/installation.md:118), nixpkgs has pkgs/by-name/ko/komorebi/package.nix. Chocolatey: not found in the repo |
gh api repos/ScoopInstaller/Extras/contents/bucket/komorebi.json; .github/workflows/windows.yaml job winget; gh api repos/NixOS/nixpkgs/contents/pkgs/by-name/ko/komorebi/package.nix; grep -i choco finds nothing |
Secrets in the Windows repo: PAT, SCOOP_TOKEN, WINGET_TOKEN (names only); KDE and macOS (public) repos list none |
gh api repos/.../actions/secrets |
Windows CI wall time: 22 to 30 minutes per run (master push 2026-10-31 01:21:55 to 01:51:51; schedule 2026-11-01 00:51:43 to 01:14:06; feature-branch pushes 15 to 22 minutes) |
gh api repos/LGUG2Z/komorebi/actions/runs timestamps |
Users of the update checks: the Windows bar and komorebic read https://api.github.com/repos/LGUG2Z/komorebi/releases/latest (komorebi-bar/src/windows/os.rs:35; komorebic/src/windows.rs:585, 950); the macOS bar reads .../komorebi-for-mac/releases/latest (komorebi-bar/src/macos/os.rs:18, 22, 123) |
git grep at 2185556efba6 |
Two premises of the brief could not be reproduced: "the 23 macOS commits that mention #N": in the macOS history only ONE commit
matches #[0-9] (6b980a03 fix(border): close nswindow on main thread, whose #0..#17 are stack frames in a log excerpt,
not issue references: inferred from the body); the KDE history has none. The 309 commits matching #[0-9] in the
merged history (git log 2185556efba6 --grep='#[0-9]') are overwhelmingly Windows commits, whose (#1234) references
are to this repository and stay correct. So nothing needs rewriting; a rewrite is excluded anyway (original hashes are a decision).
1. Branch and history mechanics
1.1 Decision and owner
Decision: how the consolidated line becomes LGUG2Z/komorebi master, and what is published first. Owner: the repository owner (the
user). Agents never push.
One gate before any option: publishing the KDE history. komorebi-for-kde is private (section 0). Pushing wip-main
publishes its 254 commits and the KDE source to a public repository. That cannot be taken back (forks, clones, GitHub's
commit cache by hash, search engines). The Windows history already public (85 commits on komomono) contains no KDE
code (it is the pre-merge tree: git -C ~/komorebi log of komomono has no komorebi-for-kde/ path; inferred from the merge order in the
progress log: A2 merged KDE and macOS on top of komomono@source). The macOS history is mostly public already (ash-squashem is a public branch of komorebi-for-mac, gh api .../branches), but the private
repository KomoCorp/komorebi-for-mac held the development (docs/macos/README.md:46-47); the 41 commits that are only on ash-squashem
are public today. The owner has decided that there is no private repository afterwards. All 254 + 304 authors are one address (LGUG2Z@fastmail.com; git log --format=%ae, plus one dependabot) so no third-party privacy question arises
from authorship. A licence question remains: the tree carries LICENSE.md "Komorebi License 2.0.0" and the Homebrew template states the same licence
(docs/dev/old-ci/macos/formula.template.rb:8). The owner decided that KDE and macOS become public with the Windows project and that there is no private mirror (R1,
answered). The push itself still needs the owner's explicit confirmation at step L3 (section 5): do not push before it.
1.2 Options
| Option | What it does | For | Against |
|---|---|---|---|
A. Fast-forward master to the cutover tip (recommended) |
master (72aa4c97) is an ancestor of the local line, so git push origin <tip>:refs/heads/master is a fast-forward, no force. komomono stays as a pointer for a while |
keeps LGUG2Z/komorebi (stars, forks, issues, PR numbers, releases/latest, Scoop/WinGet/nixpkgs URLs, cargo install --git, the update checks) and all original hashes; no history rewrite |
master changes shape in one step (see 1.4); needs a master freeze while it is prepared |
B. Make komomono the default branch, leave master |
change default branch in settings | master untouched, reversible by one setting | cargo install --git and every clone/git clone default follow the default branch, so they change anyway; 27 open PRs target master and would have to be retargeted; docs say master (mkdocs.yml, blob/master, raw.githubusercontent.com/LGUG2Z/komorebi/master/schema.asc.json); two long-lived trunks |
C. Rename branch komomono to master through GitHub's rename |
server-side rename moves PRs, protection, Pages | none over A | master already exists; renaming over it is what A does without risk. Not needed |
D. Squash or rebase the line onto master |
one new commit set | simple log | rewrites every hash; breaks the binding "original commit hashes kept" decision; needs a force-push. Rejected |
E. A new repository (LGUG2Z/komorebi-all or an organisation) |
clean start | no effect on Windows users until chosen | loses stars (15,331), forks, 755 issues, PR history, releases/latest of every installed updater; GitHub offers no way to move them. Rejected |
Recommendation: A, in two pushes: (1) push the local line to the branch komomono (a fast-forward: komomono@origin is its ancestor); review in
the browser on GitHub (compare master...komomono); (2) after the go/no-go checklist, push the same commit to master. Both pushes are
fast-forwards. Never use --force or +refspec: if a push is rejected, something moved, stop and read why.
1.3 What happens to the 85 commits already on komomono@origin
They are the first 85 of the 1110. The local line is a descendant (jj log -r 'wip-main..komomono@source' empty), so pushing wip-main onto
komomono adds 1110 commits and rewrites nothing. The 24 revisions of the cutover stack are NOT on origin yet (they exist only in
the work clone); the work clone's history of wip-cand* bookmarks is local scaffolding and must NOT be pushed (see 1.6).
1.4 Effect on open PRs, issues, forks and master users
- Open PRs (27: 19 community, 8 dependabot). Their merge base is old
master, so GitHub's diff still shows only their changes. Merging them after the cutover is a three-way merge across renames. The Windows daemon moved fromkomorebi/tokomorebi-windows/, the rootschema*.jsontoschemas/windows/, thekomorebipackage directory is nowkomorebi-daemon/(its package name is stillkomorebi;komorebi-daemon/Cargo.toml).git mergeuses rename detection, so many will merge cleanly (inferred, untested); each contributor may be asked to rebase. Whether they merge cleanly: (unknown), test on the scratch repo (section 5.4) withgit merge-treefor each head ingh pr list. Plan: before the freeze, merge or close with a comment those that are ready; for the rest post one comment with the path map (komorebi/tokomorebi-windows/,schema*.jsontoschemas/windows/,komorebi/src/main.rstokomorebi-daemon/src/main.rs) and keep them open. The 8 dependabot PRs: close them; dependabot recreates them against the newdependabot.yml(section 3.7). - Open issues (89). They stay: same repository, same numbers. Add labels
windows,linux,macosand a platform field in.github/ISSUE_TEMPLATE/bug_report.yml(Windows-only today). - Forks (376). Unaffected until they sync. A fork's
masterfast-forwards in GitHub's "Sync fork" (no divergence unless the fork's master has commits, in which case they face the rename conflicts). masterusers. Anything trackingmaster:cargo install --git https://github.com/LGUG2Z/komorebi komorebistill resolves the packagekomorebi(komorebi-daemon/Cargo.tomlname = "komorebi"), but it is now the cross-platform package, and on Windows needs thekomorebi-windowscrate, which builds (checked on the cutover stack: "Windows clippy" per the progress log). Consumers ofkomorebi-client = { git = ... }keep the package namekomorebi-client. Raw schema URLs.../LGUG2Z/komorebi/master/schema.asc.json(komorebic/applications.json:2, written into users' home bykomorebic quickstart, komorebic/src/windows.rs:354-363) and.../master/schema.json(spikes fixture) point at root files that no longer exist (schemas/windows/now). Editors lose validation for those users; nothing crashes (see 2.2b). Because the root schema files are gone (decision R5), these rawmaster/URLs stop resolving; the consequence, the tasks and the wording for the README and the release notes are in 2.2b. Tagged URLs (.../v0.1.41/schema.json, used bydocs/komorebi.example.json:2) stay valid forever (tags are immutable). The Windows tests fetch.../refs/tags/v{version}/komorebi.example.json(komorebi-windows/src/static_config.rs:1389) which also remain valid.- winget / Scoop / nixpkgs. Scoop and WinGet read releases, not branches (
checkver: github). Their asset-name patterns must be kept exactly:komorebi-<version>-<x86_64|aarch64>-pc-windows-msvc.zip,komorebi-<version>-<x86_64|aarch64>.msiandchecksums.txt(Scoop reads$baseurl/checksums.txt; adding macOS and Linux lines to the same file should be safe because the hash is looked up by file name, inferred, verify in the dry run). The Windowslatestrelease becomes the unified release, so the pattern holds only if every unified release keeps the Windows assets. nixpkgs'package.nixbuilds from the release tag source; a unified source tree changes its build (cargoBuildFlags,cargoLock): (unknown) until its maintainer is asked; open an issue on nixpkgs after 0.2.0 or send the bump yourself. Chocolatey: not present in the repository or workflows; (unknown) whether a third-party package exists.
1.5 Protection rules
Today there are none (branches/master/protection 404, rulesets 0). After the cutover add a ruleset on master and on tags v*: block force-push and deletion, require a pull request for everyone except the owner (bypass for owner), require the
one required check named ci / required (section 3). The KDE repo could not have protection at all ("Upgrade to GitHub Pro or make this repository public": gh api .../branches/master/protection), which is one more small reason to move it. The ruleset is not installed before the push because a
protected master that rejects the first fast-forward from the owner would need a bypass anyway.
1.6 What not to push
The work clone /home/jado/komomono-work/komorebi has about 60 wip-* bookmarks (jj bookmark list -a), including wip-cand1..wip-cand9, wip-u-*, ws-*, and the kde/mac remotes pointing into the scratchpad. Push exactly one commit id, never --all and never jj git push --tracked. In ~/komorebi: import the stack as one bookmark (commands in 5.3).
1.7 The old-hashes check (run before and after the push)
Evidence already seen on 2185556efba6:
git log --followandgit blamefollow the pure moves:git log --follow -- komorebi-windows/src/splash.rslists 7 commits back tob6139864 2025-10-28 feat(wm): add a splash screen for mdm devices(ran);git blame -L1,2 -- komorebi-windows/src/splash.rsnamesb61398647 komorebi/src/splash.rs (LGUG2Z 2025-10-28)(ran). The same--followforkomorebi-macos/src/splash.rsreaches the same original commit (7 commits; the macOS repository forked from the Windows history).jj file annotate -r wip-cutover-docs komorebi-windows/src/splash.rsdoes not follow the move: every line is attributed to the move revision (ywyyvwzz, 2026-11-01 07:23). Usegit blame/git log --follow(orjj file annotateat the revision before the move) for authorship. The unified-binaries note already says "jj does not follow moves" (docs/dev/unified-binaries.md).git log -- <new path>without--followshows 1 commit (the move): expected.
Checks to run on the pushed state (all read-only; expected output in brackets):
for c in 72aa4c97ade72b802a008bdba4bf59cca04df665 7d19fd404534d75edfcece09831143c36896d40b 9a58e5117afa2df6bfbe544a1c40f2534935f094 ff3711dcb5d2a1cbef5e3e91523c0183bc50343e; do
git merge-base --is-ancestor $c origin/master && echo "ok $c"; done # four "ok"
git merge-base --is-ancestor origin/master~0 origin/master # trivial
git rev-list --count 72aa4c97ade72b802a008bdba4bf59cca04df665..origin/master # equals the local count (about 1195 + the revisions added after this plan)
for t in v0.1.0 v0.1.1 v0.1.41; do git rev-parse $t^{commit}; done # unchanged Windows tags (v0.1.0 and v0.1.1 are Windows commits, not macOS)
git rev-parse 64341e29a2d55b0b2f4289687944eec5aa519136 0cc4ca7f67d79da0d59d603dde2f6b4445fec85b # the macOS v0.1.0 and v0.1.1 commits still resolve
git log --follow --format=%h -- komorebi-macos/src/splash.rs | tail -1 # b6139864
In the old repos, count what will be pointed at: git -C ~/komorebi-for-kde rev-list --count master (254) and git -C ~/komorebi-for-mac rev-list --count ash-squashem (304).
1.8 Steps (summary; commands in section 5.3)
- Freeze: no merges to
master; recordmaster's sha (72aa4c97today). 2. Rehearse on a scratch repository (5.4). 3. Fetch the final stack into~/komorebi, verify. 4. Push tokomomono(fast-forward). 5. After sign-off, push the same commit tomaster. 6. Safety branchlegacy/windows-0.1at72aa4c97(socargo install --git ... --branch legacy/windows-0.1and hotfixes for 0.1.41 remain possible). 7. Ruleset. 8. Keepkomomonofor two weeks, then delete the branch (reversible while commits are reachable frommaster).
1.9 Verify, roll back, irreversible
Verify: the checks in 1.7; gh api repos/LGUG2Z/komorebi/branches/master --jq .commit.sha equals the pushed id; GitHub's compare of 72aa4c97...master shows "ahead by N, behind by 0".
Roll back before the push to master: nothing happened (delete the scratch repo, forget the work). Roll back after: there is no safe rollback except a forward revert (a commit on master that restores the old tree) or, as a last resort, a force-push of master back to 72aa4c97 which the Windows users' clones would see as a rewritten history and which fights with every PR merged in between: do not do it; instead keep legacy/windows-0.1.
Irreversible: publishing KDE's source and history (commits become public and mirrored by forks/caches); anything a third party cloned; the tag v0.2.0 once Scoop, WinGet or nixpkgs bots picked it up (section 4).
2. The two old repositories
2.1 Decision and owner
Decision: what each old repository becomes after the cutover and for how long. Owner: the user. Recommendation: KDE: archive after the cutover (no redirect needed, it is private; nothing to keep alive). macOS: keep alive for 3 months with a README banner and a final release, then archive. "N" = 3 months is a recommendation, not a measurement: the 851 downloads of macOS v0.1.1 and the Homebrew formula suggest a small installed base, so a short window is enough; the number of macOS users still on 0.1.x is (unknown).
2.2 Issues and PRs
| Repo | Open issues | Open PRs | Method |
|---|---|---|---|
komorebi-for-kde |
1 (#6, the canary issue opened by the CI) | 0 (5 total, all closed) | close #6 with a pointer; nothing to transfer |
komorebi-for-mac |
issues are disabled (gh issue list says so); open_issues_count shows 13 but is stale or counts something the API will not list: (unknown); check the web UI |
0 (0 ever) | nothing to transfer; if the 13 are really issues, enable issues for the transfer window and use gh issue transfer N LGUG2Z/komorebi (GitHub moves issues between repositories of one owner: all three are LGUG2Z) |
komorebi |
89 | 27 | stays; the unified tracker |
Method recommendation: one tracker (LGUG2Z/komorebi), label by platform; do not transfer anything automatically. A transfer keeps the issue number-to-title mapping only through a redirect from the old URL, and the numbers change, so for 0 to 1 issues it is not worth it.
The [FEAT]: sponsor-only auto-close policy (.github/workflows/feature-check.yaml) now applies to Linux and macOS feature requests too (decided, R6); the KDE repo had no such policy. What must be rewritten for it to make sense is the task list 2.2a.
2.2a R6 task list: the sponsor-only [FEAT] policy for one public project with no private tier
Found by git grep -i sponsor on the tip (59b01fdb, plus the checks of 2185556efba6):
.github/workflows/feature-check.yaml:22(message text): names "current GitHub sponsors on the $5/month tier and above", "valid individual commercial use licence" and "approved contributors". Rewrite so it does not imply a private repository or early access, says it is for all platforms (Windows, Linux, macOS), and links the one licence page. Keep the[FEAT]:title prefix check and the close-and-lock behaviour..github/ISSUE_TEMPLATE/feature_request.yml:2,11,13,16,17,30(description "Limited to Sponsors, Commercial License Holders, and Collaborators", the sponsorship platform dropdown with GitHub Sponsor and Ko-fi, the username field): add a required platform dropdown (Windows, Linux KDE, macOS); keep or adjust the sponsor fields as the owner words them..github/ISSUE_TEMPLATE/bug_report.ymlandconfig.yml: add the platform field and fix the docs link (they point atlgug2z.github.io/komorebi/..., Windows-only) so Linux and macOS reporters are not sent to the wrong docs.README.md:16-17,102,134-152anddocs/index.md:48-65: the "Sponsorship for Personal Use" section and the sentence about "submit feature requests on the issue tracker" are written for the Windows project; reword for the three platforms.docs/linux/index.md:124-141anddocs/macos/index.md:59anddocs/macos/README.md:19-20,43-47,60: the same section is copied into the Linux and macOS indexes; remove the paragraph that says the public repository is for releases and a private one for certain sponsor tiers (docs/macos/README.md:43-47), keep or delete the copies of the sponsorship text so that there is ONE wording; check the badge lines.docs/dev/old-ci/macos/formula.template.rb(caveat about a private repository and token) is not copied into the new formula (see 2.4).- Licence:
LICENSE.md(Komorebi License 2.0.0) is the one licence; the macOS formula stateslicense "Komorebi License 2.0.0"(formula.template.rb:8) and the KDE tree had its own file merged into one at the cutover: confirm that no per-platform licence text remains (git ls-files | grep -i licen) and thatkomorebic's licence prompt text (komorebic/src/windows.rsandkomorebic/src/macos/mod.rs, which namehttps://lgug2z.com/software/komorebi) is the same on all platforms. - Decide what the policy does for PRs and for the KDE feature set that was developed privately (nothing to do in code; say it in the README).
2.2b R5 consequence: the old Windows master/ schema URLs stop resolving
No root schema.json, schema.asc.json or schema.bar.json remains (checked: none at the root of the tip). Therefore:
https://raw.githubusercontent.com/LGUG2Z/komorebi/master/schema.asc.json(the$schemaline ofkomorebic/applications.json, copied bykomorebic quickstartinto users' homes) and.../master/schema.jsonreturn 404 after themasterpush. Nothing crashes: only editor validation and completion for those users stops. Users who copied configs with.../v0.1.41/schema.jsonor another tag keep working (tags are immutable); thekomorebic quickstartof the OLD 0.1.x binaries writes themaster/URL, so every user who ran it has one.- Repository tasks: change
$schemainkomorebic/applications.jsonand inkomorebic/src/macos/applications.jsonto the per-platform path (schemas/<platform>/schema.asc.json) at the tag chosen under R5;docs/komorebi.example.json:2anddocs/komorebi.bar.example.json:2(they sayv0.1.41) to the new tag at the release; the spike fixturespikes/config-parity/fixtures/windows-kitchen-sink.jsoncan stay. - During the dev line (
masterhas the new tree but nov0.2.0tag), a tagged URL for the new paths does not exist yet; use.../master/schemas/windows/schema.jsonin the dev-line docs only, and switch to the tag at E1. - README and release notes must say, in these words or close: "The Windows schema files moved from the repository root to
schemas/windows/. A$schemaline that points at.../LGUG2Z/komorebi/master/schema.json,schema.bar.jsonorschema.asc.jsonno longer resolves; change it to.../LGUG2Z/komorebi/v0.2.0/schemas/windows/schema.json(andschema.bar.json,schema.asc.json). Lines that name a release tag keep working." Put the sentence inREADME.md(a "Upgrading from 0.1.x" note) at the dev-line landing, and inRELEASE-NOTES-0.2.0.md(4.5) as the first migration item for Windows users. Also announce it where the user community reads (the README names Discord).
2.3 Where the old names are used (classified)
Counted by git grep at 2185556efba6 (excluding docs/dev/old-ci): komorebi-for-kde 24 files / 98 lines; komorebi-for-mac 35 files / 124 lines; lgug2z.com 24 files / 37 lines;
lgug2z.github.io 5 files / 10 lines; KomoCorp 2 files / 11 lines; homebrew-tap 1 file / 3 lines.
| Class | Where | Action at cutover |
|---|---|---|
| A. Runs in a shipped binary (must change before 0.2.0, otherwise a behaviour is wrong) | komorebi-bar/src/macos/os.rs:18,22 (update check and release link to LGUG2Z/komorebi-for-mac), :123 (test strings, v0.1.2) |
point at LGUG2Z/komorebi/releases/latest; but note the Windows bar already reads the same URL: after unification the macOS and Windows bars would both see v0.2.0 and each other's tags. The release tag must therefore stay one number for all (it does), and the "is there a newer release" comparison needs no platform filter. The test at :123 must follow |
| A. Schema URLs generated into shipped schemas | crates/komorebi-config/src/changes.rs:248, crates/komorebi-bar-core/src/schema/changes.rs:29 (text becomes schemas/macos/schema*.json descriptions: "$schema: https://komorebi-for-mac.lgug2z.com/komorebi.0.2.0.schema.json") |
decide the URL scheme (R5), change the text, regenerate schemas/macos/ with just jsonschema on a Mac and the nix-options check |
| A. Application-specific config | komorebic/src/macos/applications.json:2 ($schema .../komorebi-for-mac/master/schema.asc.json) |
new path schemas/macos/schema.asc.json of the unified repo, at a tag or master |
| B. Example configs, copied into users' homes | docs/macos/komorebi.example.json, docs/macos/komorebi.bar.example.json ($schema https://komorebi-for-mac.lgug2z.com/komorebi*.0.1.0.schema.json), docs/komorebi.example.json:2 (.../komorebi/v0.1.41/schema.json) |
the 0.1.x URLs stay valid only while the hosts exist: keep komorebi-for-mac.lgug2z.com serving the 0.1.x schemas (do not delete the Cloudflare Pages project), and add the 0.2.0 schemas under the chosen scheme |
| C. Install instructions | docs/linux/installation.md:27,167,181-182 (github:LGUG2Z/komorebi-for-kde, git clone .../komorebi-for-kde), docs/macos/installation.md:48-51,80 (brew install lgug2z/tap/komorebi-for-mac-nightly, inputs.komorebi-for-mac.url = "github:KomoCorp/komorebi-for-mac"), docs/macos/README.md:43-51,272 |
rewrite to github:LGUG2Z/komorebi; the flake attribute names wait for flake-one (FLAKE_*); note nixosModules.komorebi-for-kde, overlays.komorebi-for-kde, darwinModules.komorebi-for-mac are in today's root flake (flake.nix:407-409): keep these names as aliases of the new ones for one release |
| C. READMEs and prose | README.md:72 ("The Mac port used to live in its own repository ... where this repository will be published is not decided"), docs/linux/README.md:5,81, docs/linux/dev/*.md, docs/macos/README.md badges (commented out) |
edit once the repository is final; R1 and R3 decide the wording |
| D. History, left alone on purpose | docs/dev/*.md analysis notes, docs/linux/CONTRIBUTING.md:107-108, docs/linux/dev/COMPARE.md, scripts/linux/compare-gen.py (stale, flagged in MIGRATION-SUMMARY.md section 6), crates/komorebi-version/src/lib.rs:15 (a comment link), tools/fast-check, tools/kde-closure-check, tools/e2e-needed (old directory names; tools/kde-closure-check still reads the old path of root-crates.json, MIGRATION-SUMMARY.md section 7) |
the tools lines are code: fix them in the pre-cutover stack (they affect tools/fast-check's routing, which will mis-route everything now); the prose is history |
| E. Release machinery | docs/dev/old-ci/macos/workflows/*.yaml (KomoCorp/komorebi-for-mac, LGUG2Z/komorebi-for-mac, gist 78b3dd12a7b7069f1d1c60621fe50730, LGUG2Z/homebrew-tap), formula.template.rb (homepage "https://github.com/KomoCorp/komorebi-for-mac", token header for a private asset URL) |
rewritten in section 3 and 4, not copied |
| F. Sites and links on lgug2z.com | https://lgug2z.com/software/komorebi (licence purchase, in README.md, komorebic/src/windows.rs x3, komorebic/src/macos/mod.rs, feature-check.yaml), lgug2z.com/articles/educational-source-software/, kw-icul.lgug2z.com and km-icul.lgug2z.com (splash.rs of Windows and macOS), komorebi.lgug2z.com/schema and komorebi-bar.lgug2z.com/schema (mkdocs.yml, docs/usage/*.md, docs/common-workflows/bar.md), komorebi-starlight.lgug2z.workers.dev (the reference sites, README.md, docs/macos/README.md) |
outside this repository. Which host serves which site and whether DNS stays: (unknown) (not checked; a curl -I https://komorebi.lgug2z.com/komorebi.0.1.41.schema.json returned 404, so the Windows schemas are not published under that name today) |
2.4 Crate, package and tap names
- Cargo packages that disappeared (deleted shim packages):
komorebic-linux,komorebic-macos,komorebi-client-linux,komorebi-client-macos,komorebi-bar-macos(MIGRATION-SUMMARY.md section 7). Directorieskomorebi/(Windows) iskomorebi-windows/. None of these was published to crates.io as far as the repository says (nopublishkey, nocargo publishin any workflow); whether any name was ever published: (unknown), checkcargo search komorebibefore 0.2.0. - Homebrew tap
LGUG2Z/homebrew-tap:Formula/komorebi-for-mac.rbandFormula/komorebi-for-mac-nightly.rbexist (gh api repos/LGUG2Z/homebrew-tap/contents/Formula). The template downloads from the privateKomoCorprelease with a token header (docs/dev/old-ci/macos/formula.template.rb:4-9). For the public unified repo the formula can use a plain public URL. Recommendation: keep the formula namekomorebi-for-macfor 0.2.0 (users'brew upgradekeeps working), point itsurlat the unified release assetkomorebi-0.2.0-aarch64-apple-darwin.zip; rename later with a tap rename file (inferred, Homebrew taps supportformula_renames.json). - Flake inputs of downstream users:
github:LGUG2Z/komorebi-for-kdeandgithub:KomoCorp/komorebi-for-mac. After archiving, an archived repository still serves flakes (archive is read-only, not removed), so users do not break; they stay on the frozen revision. Their inputs must be changed by hand togithub:LGUG2Z/komorebi(a tagv0.2.0ormaster). Say it in the release notes. Do not delete or rename either repository (a rename keeps redirects for git and web but not for flakegithub:inputs reliably: inferred; deleting breaks all of it).
2.5 Steps
- In each old repository, one commit on its
master(user, by hand): README banner "development moved to LGUG2Z/komorebi, 0.2.0 from ; this repository is archived on <date+3 months>" with the new install commands. Use GitHub's web editor or a clone in a temp dir; never~/komorebi*. - After the unified
v0.2.0release exists: publish the macOS assets also as a release inkomorebi-for-macnamedv0.2.0(same zip andchecksums.txt, a body that points to the unified release). Reason: the already-installed macOS bars readkomorebi-for-mac/releases/latest(komorebi-bar/src/macos/os.rs:18) to show an update, and old formulas read this repository; without this, 0.1.x macOS users are never told. The old workflow already published each macOS release in both repos (docs/dev/old-ci/macos/workflows/release.yaml "Create release on public repo"). - Close KDE issue #6 and the macOS stale issues, archive KDE immediately, macOS at +3 months (Settings, Archive: reversible).
- Keep the Cloudflare Pages project and DNS for
komorebi-for-mac.lgug2z.comas they are (schema URLs of released 0.1.x configs). - Rotate the token named above, and every PAT whose name appears in the old workflows:
GH_USER_API_TOKEN,PAT,SCOOP_TOKEN,WINGET_TOKEN(the last two are in use by the Windows repo; rotate only if exposure is suspected).
2.6 Verify, roll back, irreversible
Verify: gh repo view LGUG2Z/komorebi-for-mac --json isArchived,description; brew fetch of the formula; open an old macOS bar against a test release. Roll back: archive and README banner are reversible. Irreversible: deleting either repository (stars 261, forks 4 vanish), a rename (breaks flake inputs), transferring ownership away (not proposed).
3. CI
3.1 Decision and owner
Decision: the one workflow set, runners, triggers, what is a nix check and what is cargo. Owner: the user (cost, self-hosted hardware, secrets). Agents may only draft. Nothing here is created under .github/; the drafts are in Appendix A.
3.2 What exists (read)
| Old workflow | Jobs and facts (file) |
|---|---|
Windows .github/workflows/windows.yaml |
cargo-deny (ubuntu-22.04); build matrix windows-latest x x86_64-pc-windows-msvc and aarch64-pc-windows-msvc: CRLF check, cargo +nightly fmt --check, cargo clippy, cargo test, houseabsolute/actions-rust-cross release build, cargo wix --no-build -p komorebi ... -I .\wix\main.wxs, upload artifact (14 days) with Swatinem/rust-cache; nightly (schedule 30 0 * * 0 = every Sunday, the comment says "every day": the comment is wrong, only on master; deletes and recreates the nightly prerelease, notes by kokai), release-dry-run (draft release), release (on v* tags, softprops/action-gh-release@v2), winget (vedantmgoyal2009/winget-releaser@main, WINGET_TOKEN). Triggers: PR, push to master, feature/*, hotfix/*, tags v*, schedule, dispatch. permissions: write-all |
Windows feature-check.yaml |
closes [FEAT]: issues unless a condition stated in its message holds (see R6) |
KDE docs/dev/old-ci/linux/workflows/ci.yaml |
all jobs guarded by github.repository == 'LGUG2Z/komorebi-for-kde'; cargo-deny; checks (3 shards by regex: rust, guests, rest, all as nix build of checks.x86_64-linux.* except vm-*, fail-fast: false); lint (nix develop --command just lint); discover (reads legacyPackages.x86_64-linux.vmTiers); vm-fast (one runner per suite, KVM, 45 min timeout, nix build .#checks.x86_64-linux.vm-<suite>); vm-slow (master, schedule, dispatch or PR label ci:vm-slow; 60 min; runs the test driver outside the sandbox to upload screenshots and journals); canary (weekly: moves nixpkgs to the tip in a copy, builds every check, VM tiers included, one machine, 360 min timeout, opens or updates an issue); build (x86_64 on ubuntu-24.04, aarch64 on ubuntu-24.04-arm continue-on-error; patchelf to the system loader; runs --version); publish (tags v* and the nightly prerelease from master schedule/dispatch; zip per target, schema.json, checksums.txt, kokai@0.3.1 notes) |
KDE actions/nix/action.yaml |
frees disk on KVM jobs (a Plasma guest is about 10 GB), enables KVM through a udev rule and fails with a named step "Enable KVM" when absent, cachix/install-nix-action@v31, no Cachix service is used ("no Cachix cache, account or token is configured"), cache nix-community/cache-nix-action@v7 keyed on flake.lock and **/Cargo.lock with gc-max-store-size-linux: 8G |
KDE rerun-no-kvm.yaml |
reruns failed jobs up to 3 attempts when every failure is the "Enable KVM" step; runs on workflow_run of ci. Observed: 5 runs in the history |
KDE update-flake-lock.yaml |
Mondays 03:00 UTC, DeterminateSystems/update-flake-lock@v29, PR "chore(deps): flake.lock: Update" |
macOS docs/dev/old-ci/macos/workflows/nix.yaml |
runs-on: self-hosted, guarded to KomoCorp/komorebi-for-mac: nix flake check, nix build, upload result/bin/komorebi*, on master deploy schema.json to a gist (exuanbo/actions-deploy-gist, secret GH_USER_API_TOKEN), on master schedule/dispatch publish the nightly prerelease and push a generated formula to LGUG2Z/homebrew-tap |
macOS release.yaml |
manual dispatch with a tag; checks that the tag is at the same commit in both the private and public repositories; nix flake check, nix build, zip komorebi-<tag>-aarch64-apple-darwin.zip (the name includes the v of the tag; Windows and Linux names do not) and checksums.txt; creates the release in both repos |
Three dependabot.yml |
github-actions and cargo, weekly, assignee LGUG2Z, commit prefix chore with scope: the Windows one is live, the other two identical (docs/dev/old-ci/*/dependabot.yml) |
3.3 Proposed design
Principles: (1) required check = one job, required, that depends on the others so protection names one check; (2) everything that runs without a window system runs on the PR; (3) anything that needs KVM or a Mac or the evaluation Windows image does not run on fork PRs; (4) nix checks are the unit of truth for lint/clippy/nextest/doc/deny/fmt of each platform because the old repos already gate on them (the cutover docs list them, docs/dev/build-and-test.md sections 1-3); cargo jobs only where Windows or macOS must run natively (the MSI, cargo test on Windows).
| Job | Runner | Needs | Runs on | What |
|---|---|---|---|---|
deny |
ubuntu-24.04 |
PR, push master, schedule |
EmbarkStudios/cargo-deny-action@v2 with the one root deny.toml (the cutover merged them) |
|
nix-checks (3 shards, as KDE did: rust / guests / rest) |
ubuntu-24.04 |
PR, push | nix build of FLAKE_CHECKS_windows, FLAKE_CHECKS_linux: fmt, toml-fmt, deny, clippy, nextest, doc, schema-fresh, nix-options. Windows clippy is the 3.5-minute pre-landing gate with warm dependencies (docs/dev/build-and-test.md section 1) |
|
windows-build |
windows-latest x two targets |
PR, push, tag | as today: CRLF check, cargo +nightly fmt --check, clippy, cargo test, release build, cargo wix -p komorebi. cargo test now sees the Linux and macOS crates compile empty on Windows (target-gated; progress log) |
|
macos-build |
macos-14 or macos-latest (arm64, hosted) or the existing self-hosted Mac |
PR, push | cargo build/clippy/test --locked for the packages in docs/dev/build-and-test.md section 3 (665 tests, 0 failed on the Mac Mini at candidate 8 per MIGRATION-SUMMARY.md section 4) and the darwin nix checks FLAKE_CHECKS_macos. No daemon is started: nothing in CI can verify tiling on macOS (no accessibility grant, no display). A hosted macOS runner can compile and unit-test: (inferred, never tried here) |
|
vm-fast (matrix over FLAKE_VM_TIERS.fast, 16 suites) |
ubuntu-24.04 with KVM |
discover |
not on fork PRs; on PRs from the repository, on master push, nightly |
one runner per suite, 45 min timeout each, as before. KVM on hosted runners is documented for public repositories only (docs/dev/old-ci/linux/actions/nix/action.yaml:20-21); some runner hosts have none, hence rerun-no-kvm which stays |
vm-slow (18 suites) |
same | nightly, master push, PR label ci:vm-slow |
as before, uploads screenshots and journals (7 days) | |
e2e-windows |
self-hosted, label kvm-windows-e2e (the user's machine) |
windows-build is not required |
PR label ci:e2e by a maintainer; nightly subset; weekly full; before a release: full |
needs KVM, the Windows 11 Enterprise Evaluation ISO (go.microsoft.com/fwlink/?linkid=2289031), a golden image built locally (the base layer is built once and again "when the 90-day evaluation runs out", e2e/platforms/qemu_windows/README.md:9-26); about 4 vCPU and 6 GB per scenario guest. Cannot run on a hosted runner (inferred: the image is a local multi-GB artifact and the licence is an evaluation) |
canary |
KVM runner, 360 min | weekly | as the KDE one: move nixpkgs, build every check against it, open or update an issue. Make it one job per platform group so it does not need 6 hours on one machine | |
release |
see section 4 | required |
tag v* |
|
rerun-no-kvm |
ubuntu-24.04 |
workflow_run |
unchanged | |
update-flake-lock |
ubuntu-24.04 |
Monday 03:00 | DeterminateSystems/update-flake-lock@v29; the PR runs the full PR set |
|
feature-check |
ubuntu-latest |
issues opened | unchanged unless R6 says otherwise |
Triggers: pull_request (all branches), push to master only (the old feature/* and hotfix/* pushes also built; on a one-maintainer repo with a PR flow they double the cost: drop them, keep hotfix/* if hotfixes are pushed without a PR), tags v*, schedule nightly 30 0 * * * for the nightly prerelease plus the e2e/VM/canary sweeps, workflow_dispatch. Note: the old schedule was weekly (30 0 * * 0), and the comments in two workflows say "every day": the nightly prerelease has been weekly in fact.
Windows e2e subset. Measured: 47 scenarios, 2.2 min typical (commands 6.2 min), first pass 19:54 to 21:45 = about 111 minutes, plus reruns and the soak (progress log "gate cand8"). The 22-scenario targeted gate took 00:33 to 01:25 (2.5-2.8 min each, commands 5.6; progress log "gate cand9"). Proposal:
- PR (only when
tools/e2e-neededsays YES, it reads the Cargo closure of the Windows binaries and answers whether an e2e is owed): the cluster named in the change pluscommands, run on the self-hosted machine when the labelci:e2eis set. About 3 to 15 minutes. - Nightly: the 22-scenario set of the cand9 gate (commands workspaces focus stacks monocle floating maximizing rules rules_class rules_exe manage_rules startup_rules title_rule layouts config_reload lifecycle handover resize lifecycle_hidden hotplug promoting): about 1 hour.
- Weekly and before a release: all 47: about 2 hours.
Known failures (docs/dev/build-and-test.md section 6): four stale known-failure markers (
maximizing.user,placement,unknown_monitorx2) fail on every commit,fullscreenfails 2 checks on baseline too (progress log 2026-11-01 00:30), acommandslock-hold stall about 1 in 10-12 sweeps. A green required status cannot be had from the full set until the four stale markers are re-marked andfullscreenfixed or marked: re-mark them first (R4).
KDE VM tiers. fast (16 suites: check hotplug commands kwin-restart kwin-events scrolling workspace-rules core-e2e kwin-contract kwin workspace-switch stacks module placement user-maximize run-kde) on PRs from the repository and on master; slow (18 suites) nightly and by label. One hosted runner each, in parallel, each up to the old 45/60 min timeouts. Measured on the user's host, not hosted: commands 1347 s at load about 2; the whole 16-suite cand9 run took about 65 minutes sequentially (00:02 to 01:07, progress log). Hosted wall time per suite: (unknown); the old repo's ci runs on master failed within 7 to 10 seconds on push (2026-10-31 01:58 and 01:41) and about 10 minutes on the scheduled run (2026-11-01 00:50 to 01:01); the cause is (unknown) (not read: the job logs need gh run view --log, not run).
Caching. No Cachix was ever used (action.yaml comment). The nix store cache keyed on flake.lock and Cargo.lock, 8 GB cap. One repository now carries a Windows, a Linux and a Darwin closure and the GitHub per-repository cache quota is small (inferred: 10 GB for GitHub Actions caches; check current limits): the three would evict each other. Options: (a) a key prefix per job group and smaller gc-max-store-size; (b) a Cachix cache (new account, a token secret, cost (unknown)); (c) the user's own cache (Attic or S3) fed by the self-hosted machine. Recommendation: start with (a), measure the hit rate in the dry run, escalate to (b) only if PR time exceeds 30 minutes. Cargo jobs: Swatinem/rust-cache@v2 as today.
Cost and time. Public repositories do not bill hosted Linux and Windows minutes (inferred, GitHub's public-repo policy; macOS hosted runners are also free for public repos at the time of writing, check). The private KDE repository did bill. I found no billing data and do not give a cost figure. Times that were read: Windows workflow 22-30 minutes; KDE vm-fast timeout 45 min per suite in parallel; the PR critical path is therefore about the slowest of: Windows build 22-30 min, a VM suite up to 45 min, nix checks (Windows clippy 3.5 min warm, cold is (unknown); the KDE shard run out of resources at about six minutes before it was sharded, ci.yaml comment lines 41-43).
Concurrency and permissions. Add concurrency: group: ci-${{ github.ref }}, cancel-in-progress: true for PR runs, but not for master or tag runs. Replace permissions: write-all (windows.yaml build, nightly, release) by contents: read at workflow level and contents: write only on release jobs. Self-hosted runner: never run fork PR code (a fork can edit the workflow): gate the job with github.event.pull_request.head.repo.full_name == github.repository.
Secrets needed and who holds them. WINGET_TOKEN (exists), SCOOP_TOKEN and PAT (exist; what PAT and SCOOP_TOKEN are used for is (unknown): no workflow in the repository reads them, they may be for the Scoop bucket or leftover), a token to push the Homebrew formula to LGUG2Z/homebrew-tap (the old macOS workflow used GH_USER_API_TOKEN: create a fine-grained PAT limited to that repository, contents write), a Cloudflare token only if schema publishing moves into CI (just schemapub uses npx wrangler pages deploy, run by hand today), a cache token if Cachix. No signing secret exists anywhere: the Windows MSI is unsigned (nothing in windows.yaml signs) and the macOS formula ad-hoc signs at install (codesign --force -s -, formula.template.rb:19-21). The user holds all of them.
3.4 Dependabot
One .github/dependabot.yml with ecosystems cargo (/), github-actions (/) and nix (/, flake.lock; supported ecosystem name nix (inferred): the existing workflow update-flake-lock already does this weekly, so choose ONE: keep update-flake-lock and do not enable nix in dependabot), weekly, assignees: LGUG2Z, commit-message: prefix chore, include scope. Add groups: for cargo (one PR for patch/minor) because one lock now serves three platforms and 900 packages (docs/dev/unified-binaries.md: "859 packages (root) -> 900") and eight separate PRs per week would be noise. The pip entry that GitHub auto-created in the KDE repo ("Graph Update: pip in /nix/tests/vm/lib") is the dependency graph for the VM library's Python, not a config entry.
3.5 Steps
- Draft files in a revision on top of the cutover stack (user reviews):
.github/workflows/ci.yaml,e2e.yaml,release.yaml,canary.yaml,rerun-no-kvm.yaml,update-flake-lock.yaml, and.github/dependabot.yml(Appendix A). 2. Dry-run them on the scratch repo (5.4). 3. Land them together with themasterpush; the first run onmasteris the only one that runs for the first time in public. Constraint from the decisions: no KDE or macOS workflow runs before the cutover. Satisfied because workflows only trigger onmaster, PRs and tags andkomomonois none of these (a PR fromkomomonotomasterWOULD run them: do not open one; pushmasterdirectly).
3.6 Verify, roll back, irreversible
Verify: every job green on the scratch repo with the three real runners (hosted Linux with KVM, hosted macOS, the self-hosted Windows host). Roll back: delete or disable workflows (Actions tab) or revert the commit; runs and caches vanish with retention. Irreversible: workflow runs and Actions logs in the public repository; consumed secrets if mis-scoped (rotate).
4. The 0.2.0-dev landing and the release of 0.2.0
4.1 Decision and owner
Two phases (owner decision 3). Dev-line landing: komomono to master with the workspace at 0.2.0-dev; no tag, no GitHub release, no
Scoop/WinGet/Homebrew/schema/docs publication, no announcement; CI on (it builds artefacts as workflow artifacts only, and the
weekly nightly prerelease is NOT enabled until the release phase, because nightly is a published release that Scoop-like consumers
and the update checks could see: disable the nightly publish step, or keep it to the dev line only once the owner says so). Consequence for users:
releases/latest stays v0.1.41, so the Windows update check, Scoop, WinGet and nixpkgs see no change; only people who build or install
from master see the new tree (1.4). Release: a revision on master that sets the version to 0.2.0, then the tag, artefacts and announcement
(4.2 to 4.7). Decision: tag, artefacts, notes, channels. Owner: the user (secrets, announcements).
4.2 Version and tag policy
- One version:
[workspace.package] versionwas"0.2.0"(Cargo.toml:61 at2185556efba6) and is0.2.0-devon the line to land (as told by the coordinator, not re-read); the schemas sayv0.2.0(commitb8bbad87): check that schema description text andCargo.lockare consistent with0.2.0-dev, and regenerate both in the release revision (E1).komorebi-versionis one crate. During the dev line nov0.2.0*tag exists (av0.2.0-devtag is not proposed either: av*tag triggers the release workflow and Scoop/WinGet bots). Tagv0.2.0(release phase only) annotated, on the commit ofmasterthat passed the gates, pushed alone:git tag -a v0.2.0 -m "komorebi 0.2.0" <sha>;git push origin v0.2.0. - Why v0.2.0 is monotonic for everyone: Windows is at 0.1.41, macOS at 0.1.1 (the bar even has a test string for
v0.1.2), KDE never released. Semver orders 0.2.0 above all. - Old tags: leave Windows
v0.1.*as they are. The macOS tagsv0.1.0,v0.1.1,v0.1.0-prereleasecollide in name with Windows ones and were not imported; if the commits should be findable by name in the unified repository, createmacos-v0.1.0-prerelease,macos-v0.1.0,macos-v0.1.1pointing atebbd9eee,64341e29,0cc4ca7f(which are ancestors, section 0). The oldnightlytags are moving tags: the unifiednightlyreplaces them; the macOSnightlycommit6ab9f56ais not in the work clone's object store (missing), so nothing points to it, and it need not. - Release note policy: one release
v0.2.0of the repository with all platforms' assets. The release notes:kokai release(what the old workflows used) lists the commits between the previous tag and the tag; with 1195 commits sincev0.1.41this is useless as notes. Write them by hand (4.5); keepkokaionly fornightly.
4.3 Artefact matrix
| Platform | Artefacts | Built by | Name pattern (keep stable for Scoop/WinGet) |
|---|---|---|---|
| Windows x86_64 and aarch64 | zip of the .exe files (komorebi, komorebic, komorebic-no-console, komorebi-bar, komorebi-gui, komorebi-shortcuts per windows_targets in justfile), MSI by cargo wix -p komorebi -I .\wix\main.wxs, checksums.txt |
windows-build job (cargo, MSVC), not nix |
komorebi-<ver>-<target>.zip, komorebi-<ver>-<arch>.msi as in windows.yaml; wix/main.wxs Product UpgradeCode F8B967B5-... must not change (a major upgrade keeps replacing the old install) |
| Scoop | manifest in ScoopInstaller/Extras (autoupdate by bot) | their bot, from checkver: github |
needs the zip names above |
| WinGet | LGUG2Z.komorebi via winget-releaser on a published release |
winget job |
needs the MSI names |
| Linux (KDE) | zip of komorebi, komorebic for x86_64 and aarch64 (patchelf'ed to the system glibc loader, as the old build job did), schema.json; the NixOS module and overlay through the flake; no tarball existed |
nix (FLAKE_LINUX_PKGS), ubuntu-24.04 and ubuntu-24.04-arm |
komorebi-<ver>-x86_64-unknown-linux-gnu.zip |
| macOS aarch64 | zip of komorebi, komorebic, komorebi-bar (nix result/bin/*), checksums.txt, Homebrew formula, the nix-darwin module through the flake |
nix on a Mac (FLAKE_MACOS_PKGS) |
komorebi-<ver>-aarch64-apple-darwin.zip (no leading v: the old release.yaml included it, komorebi-v0.1.1-...; choose the Windows form) |
| Schemas | schemas/{windows,linux,macos}/schema*.json attached to the release and published to the schema host |
just schemapub (Cloudflare Pages komorebi, copies schemas/<platform>/) |
per-platform files in the repository (decided); the published names are the open part of R5 |
| Docs | Windows mkdocs to gh-pages (mkdocs gh-deploy: the last commit on gh-pages is "Deployed 8f982e45 with MkDocs version 1.6.1", i.e. a manual deploy, no workflow builds it); the Starlight reference by just docgen starlight <repo> |
by hand | mkdocs.yml now exclude_docs /linux/, /macos/, /dev/ (commit 4eae178f): Linux and macOS docs are NOT on the Windows site; decide where they publish (R3) |
crates.io: no crate is published today as far as the repository says; do not start with 0.2.0.
4.4 Secrets and holders
WinGet PAT (WINGET_TOKEN), Scoop (SCOOP_TOKEN, role unknown), a tap token (new, fine-grained), Cloudflare (schemas, only by hand today), none for signing (no signing exists). All held by the user. Agents never receive them.
4.5 What a user of each old project must change (the release notes skeleton)
Read from docs/dev/MIGRATION-SUMMARY.md and docs/dev/known-issues.md; what is NOT known is marked.
- Windows 0.1.41 users. The configuration file and
komorebiccommands are meant to be unchanged: MIGRATION-SUMMARY.md section 2 says the Windows state JSON "is unchanged by the shared Monitor/Workspace (platform extras are flattened in, pinned by tests)" and the schemas are pinned byte for byte; the CLI pages (docs/cli) were the oracle. Behaviour changes to mention:komorebic visible-windowsnow lists unreadable windows with empty strings (decision 14); the runtimerequiredorder in generated schemas may change (decision 11); windows rendering of the bar falls back to software OpenGL (wgpu) when OpenGL 2.0 is missing (decision 21). A sharedkomorebi-clientstill exports the same crate name.cargo install --path komorebifrom a clone becomes--path komorebi-daemon(docs/installation.md:118). Whether a user-visible change exists that the e2e did not catch: (unknown); the Windows e2e passed on cand9 except the known failures (below). - KDE users (the private repository: mostly the owner). The repository, the flake input (
github:LGUG2Z/komorebi-for-kdetogithub:LGUG2Z/komorebi), the module names (kept as aliases),schemalocation;komorebicfor KDE got the pointer-picks-the-monitor preamble forfocus-workspace*(known-issues.md section 1, decision 19) and the Windows-wording help texts of fifteen subcommands (progress log: "fifteen subcommands whose help differed join Messages with one help text"). Config:StaticConfigis one union type with per-platform views (decision 4); the KDE schema is checked in underschemas/linux. - macOS 0.1.x users. Flake input
github:KomoCorp/komorebi-for-mac(private) orgithub:LGUG2Z/komorebi-for-mactogithub:LGUG2Z/komorebi; brew formula name unchanged;$schemaURL of the config files (R5);komorebi-barandkomorebicare in the same zip as before; behaviour changes that nobody has seen on a Mac: hiding, the id registry, the shared Container API, settings snapshot, pointer picks the monitor, bar clicks (MIGRATION-SUMMARY.md section 5): all the subject ofdocs/dev/macos-hand-check-plan.md. Say so in the notes or do not ship macOS (5.2). - All: one version number across platforms;
komorebi --versionprints 0.2.0 on Windows, Linux and macOS (the three are one crate,komorebi-version); the macOS bar update check now points at the unified repository (class A above). - Known issues to list (docs/dev/known-issues.md): items 2, 3 (inherited, pinned by tests), 4 (macOS subscriber stall); the Windows
commandsstall (about 1 in 10-12 sweeps, cause not found);fullscreenfails 2 checks on baseline too; the four stale e2e markers.
4.6 Steps (release phase only, after section 5's release gates; E1 and E2 come first)
E1. A revision chore(version): 0.2.0 setting the workspace version to 0.2.0 and regenerating the schemas, Cargo.lock and the nix options; re-run the gates (5.2) on it. E2. Write docs/dev/RELEASE-NOTES-0.2.0.md (4.5). Then:
git tag -a v0.2.0 <sha>and push the tag (thereleaseworkflow builds, withdraft: truefirst: the oldrelease-dry-runjob already creates a draft release; keep the draft step). 2. Check the draft's assets against the pattern table, the checksums, run each binary's--version(the old Linux job did this on the runner). 3. Publish the release (the draft turns to published;winget-releaserruns on publish). 4. Push the Homebrew formula (formulakomorebi-for-mac,url= the public asset, no token header; delete the "requires a private repository" caveat). 5.just schemapubfor each platform (R5). 6.mkdocs gh-deploy; deploy the Starlight reference. 7. The macOS mirror release inkomorebi-for-mac(2.5 step 2). 8. Announce (the owner's channels, Discord is named in the README:README.md"you can ask on Discord"; nothing is posted by an agent). 9. Close or update the open PR comments; flip the README "not decided yet" text.
4.7 Verify, roll back, irreversible
Verify: gh release view v0.2.0, install each channel on a clean machine (Windows: the MSI over 0.1.41 as a major upgrade, which wix/main.wxs MajorUpgrade supports; Linux: the NixOS module in a VM (the VM suite module covers it); macOS: the formula on a Mac that is not the live one). Roll back: delete the draft; after publish: delete the release and tag only if no bot has run; mark Pre-release rather than delete if one has. Irreversible once consumed: a published tag and release that Scoop (autoupdate), WinGet (PR to winget-pkgs) and any nixpkgs bot picked up; downloaded installers; announcement posts.
5. Sequencing and gates
5.1 Order of the irreversible steps
Phase 1: DEV-LINE LANDING (0.2.0-dev, no tag, no release artefacts, CI on)
| # | Step | Reversible? | Gate before it (go/no-go) |
|---|---|---|---|
| L0 | Rotate the leaked macOS token; answer R3, R4, R7 to R12 (R1, R5, R6 decided; R2 and the R5 file names are release questions); do the R6 text rewrites (2.2a) before CI goes on | yes | the user's answers |
| L1 | Freeze master, triage the 27 PRs, record master sha |
yes | nobody pushes master meanwhile |
| L2 | Scratch-repo dry run (5.4) of push and CI (the release part is rehearsed later, E0) | yes (delete the scratch repository) | CI files drafted |
| L3 | Push komomono (fast-forward) |
partly: the private KDE and macOS histories become public | the owner confirms the push itself (decision 1) |
| L4 | Review on GitHub, then push master (fast-forward) |
no (see 1.9) | gates of 5.2 (dev-line column) green on the exact commit |
| L5 | Ruleset, legacy/windows-0.1 branch; CI runs on master |
yes | |
| L6 | Old repos: README banner pointing at the dev line; nothing archived yet (the release is what users are told to install) | yes | after L5 |
Phase 2: RELEASE of 0.2.0 (later, when the owner decides)
| # | Step | Reversible? | Gate before it (go/no-go) |
|---|---|---|---|
| E0 | Dry run of the release (draft, -rc tag on the scratch repo) |
yes | CI green on master for the dev line |
| E1 | Revision setting version 0.2.0, regenerate schemas and lock |
yes until pushed | gates of 5.2 (release column) |
| E2 | Release notes | yes | |
| E3 | Tag v0.2.0, draft release |
draft yes | full Windows e2e and KDE fast+slow on the tagged commit; macOS decision (R2) |
| E4 | Mirror macOS release in komorebi-for-mac (only if macOS ships) |
yes | |
| E5 | Publish; WinGet/Scoop/tap/schemas/docs; enable nightly |
no once consumed | the release checklist in 5.5 |
| E6 | Announce | no | after E5 verified |
| E7 | Archive KDE repo | yes | after E5 |
| E8 | Archive macOS repo (+N months) | yes | N months passed |
5.2 Gates on the final tree, and the open findings
The gates that exist: Windows e2e (QEMU, section 3), KDE VM fast and slow, the nix check groups of each platform, native tests (cargo test --workspace on Linux: 96 test binaries per the progress log), macOS compile/clippy/unit tests on the Mac Mini (665 passed, 0 failed, 1 ignored at candidate 8). State at the last landing (progress log 2026-11-01 01:08): all gates green on wip-cand9b (21cf0d73 = wip-main): KDE VM cand9 16/16, Windows targeted gate cand9 22 scenarios green but for the stale maximizing.user marker, nix Windows and KDE groups and packages pass, Mini cand9b green. What was NOT run on the final tree: the KDE slow tier (18 suites) was never run on any candidate (MIGRATION-SUMMARY.md section 5), the full 47-scenario Windows set on cand9/the cutover stack (cand8 ran it; cand9 ran 22), anything on the cutover stack (renames, version 0.2.0, docs, and the flake rewrite): the renames moved every directory so every gate must be re-run once on the tip, since a rebase invalidates a claim (decision 26). The progress log records "verified: Windows clippy, Linux tests 96 binaries, macOS fake-CC check" for the cutover stack, not the e2e or VM or nix builds.
The macOS hand-check pass (docs/dev/macos-hand-check-plan.md, about 5 hours on a real Mac, never run; blocks 0-8, table line 288 "total about 5 hours"). It gates the RELEASE, not the dev-line landing (owner decision 3): landing 0.2.0-dev on master publishes source, not a build anyone is told to install. Release options: (1) block the release until it is done, (2) release Windows and Linux 0.2.0 and macOS later, (3) release all three. The macOS code has never run as a daemon in these builds (MIGRATION-SUMMARY.md section 5) and changed substantially (shared Container, registry, settings, hiding): the risk is a user installing a window manager that does not hide windows. Recommendation: (2) unless the user does the pass first (blocks 0 to 4 are the "could make the daemon unusable" ones: about 2.7 hours: 25+40+45+40+10 min per the block headers); otherwise do not publish the macOS artefact or Homebrew formula under 0.2.0, keep macOS users on komorebi-for-mac 0.1.1 (so the old repository stays un-archived) and publish macOS as a separate pre-release after the pass. The unified version then has a hole: macOS goes 0.1.1 to 0.2.1, or v0.2.0 carries no macOS asset. R2. Gates by phase: dev line = the existing green gates re-run on the tip after the renames and the flake (Windows e2e targeted set, KDE VM fast, nix groups, native tests, Mac Mini compile/unit); release = the dev-line gates plus the full 47-scenario Windows set, KDE slow, and the macOS pass if macOS ships.
Open findings as release blockers or not (docs/dev/known-issues.md, build-and-test.md section 6, progress log):
- not blockers (inherited behaviour, pinned by tests): known-issues 2 (
Monitor::focus_workspaceoverwrites a name), 3 (remove_containerfocus), 4 (macOS subscriber with no write timeout), mention in notes; - not a blocker but must be marked, not left failing: the four stale e2e markers and
fullscreen(fails the same 2 checks on baseline, cand1, cand5, cand8: "does not take the window out of fullscreen", "not on any other window"; pre-existing, not a regression): re-mark so a green nightly is possible (R4); - blocker-candidate: the Windows lock-hold stall (
commandsstops answeringkomorebic statefor 3 to 3.6 s about 1 in 10-12 sweeps; longest hold 5746 ms at cand9 vs 8250 at cand5; cause not found): it exists on the baseline (1/10 before the consolidation) so it is not a regression; ship with a known-issue entry (R4); known-issues.mditself has no entry forfullscreenyet (grep of the file shows none): add it before release.
5.3 The git commands (to be run by the user, never by an agent)
All commands assume ~/komorebi is the user's repository (jj colocated), origin = GitHub. They are written down, not run.
# L1 record the base and freeze (nothing is pushed)
git -C ~/komorebi fetch origin
git -C ~/komorebi rev-parse origin/master # expect 72aa4c97ade72b802a008bdba4bf59cca04df665 (or newer: then merge, do not fast-forward)
gh api repos/LGUG2Z/komorebi/branches/master --jq .commit.sha
# L3 (before the push) import the final stack as ONE bookmark (D1 in the decisions log describes the work clone)
cd ~/komorebi
jj git remote add work /home/jado/komomono-work/komorebi # once
jj git fetch --remote work --branch wip-cutover-final # bookmark that the coordinator sets after flake-one lands
jj log -r 'komomono@origin..wip-cutover-final@work' --no-graph -T 'commit_id.short()++"\n"' | wc -l # about 1110 + the cutover stack
jj log -r 'wip-cutover-final@work..komomono@origin' # must be EMPTY (the local line contains origin's komomono)
# L3 push komomono: a fast-forward of origin's komomono, never --force
jj bookmark set komomono -r wip-cutover-final@work # a forward move; jj refuses a sideways move without --allow-backwards
jj git push --bookmark komomono # pushes ONLY this bookmark
# equivalent with git, as a double check that it is a fast-forward:
git merge-base --is-ancestor origin/komomono "$(jj log -r komomono --no-graph -T commit_id)" && echo fast-forward
# L4 after sign-off: master gets the same commit (fast-forward)
jj bookmark set master -r komomono
jj git push --bookmark master # rejected if master moved: STOP, do not force
git branch legacy/windows-0.1 72aa4c97ade72b802a008bdba4bf59cca04df665
git push origin legacy/windows-0.1
# E3 (RELEASE phase only, never during the dev line) the tag
git tag -a v0.2.0 -m "komorebi 0.2.0" "$(jj log -r master --no-graph -T commit_id)"
git push origin v0.2.0
# macOS historic tags, optional:
git tag macos-v0.1.1 0cc4ca7f67d79da0d59d603dde2f6b4445fec85b && git push origin macos-v0.1.1
jj git push --bookmark master refuses a non-fast-forward move by default and prints the reason; if it does, do not add --allow-... flags. Check before each push with jj git push --dry-run --bookmark komomono (jj 0.2x+; the installed jj version was not checked, git push --dry-run origin <sha>:refs/heads/master is the git equivalent).
5.4 Dry run on a scratch repository (proposed, not created)
Create (by the user) a private repository LGUG2Z/komorebi-dryrun (or a fork under another account, since forks of a public repo are public) and: (1) push the same single commit as master, two tags v0.2.0-rc1 and nightly; (2) add the Actions secrets as dummies (WINGET_TOKEN=dummy) so that jobs which publish fail at the publish step, not before; (3) give it the self-hosted runner label, a Linux KVM-capable hosted runner (private repositories may land on a host with no /dev/kvm: that is the failure rerun-no-kvm was written for), a macOS runner; (4) run the whole ci once, the nightly, a release from the -rc1 tag with draft: true; (5) check the checksum file with Scoop's rule by running scoop's checkver/autoupdate locally (checkver.ps1 against the scratch release) and winget-releaser in --dry-run style input if available (unknown); (6) git merge-tree of each of the 19 open community PR heads against the pushed master to count clean merges; (7) delete the repository. Cost: private-repo Actions minutes are billed on a Free plan: (unknown); to avoid it make it public for the hour and delete it, but that publishes KDE history: do not do that before the owner has confirmed the push (L3). A tree with the KDE source removed would not be the tree under test.
5.5 Go / no-go checklists
Dev-line landing checklists
Before L3 (push komomono): the owner has confirmed the push (decision 1: the KDE and macOS private histories become public); token rotated; the old-hash script (1.7) on the work clone gives four ok; jj log -r 'wip-cutover-final@work..komomono@origin' empty; the flake has landed (names resolved) and the docs name its outputs; the version on the line is 0.2.0-dev; no secrets in the pushed tree (git grep -nIE '(ghp_|github_pat_|x-access-token)' <sha> returns nothing: not run, run it) and no large artefacts tracked.
Before L4 (push master): L3 reviewed in the GitHub compare view; CI files dry-run green on the scratch repo with the nightly publish and any release/winget/tap job disabled or unable to fire (no v* tag; nightly publish step off); the dev-line gates of 5.2 re-run on the tip commit and logged; the PR triage done; master sha unchanged since L1; R3 (docs host) answered; a person is ready to watch the first CI run. The macOS hand-check is NOT required here.
Release checklists (later)
Before E3 (tag): E1 revision gated again on its own tip (a rebase invalidates a claim); full Windows e2e (47 scenarios) and KDE VM fast and slow on the exact commit; R2 answered, and if macOS ships, the macOS hand-check blocks 0 to 8 (at least 0 to 4) done and logged; known issues entries written (R4); release notes written.
Before E5 (publish): draft assets match 4.3; checksums verified; MSI major-upgrade install tested over 0.1.41 in the Windows e2e guest or a VM; the Linux zip's binaries run on a plain Ubuntu runner (--version); macOS decision applied; the notes include the migration skeleton (4.5) and known issues; WINGET_TOKEN valid; the published schema names (R5) decided.
6. Risks and open decisions for the user (answer in one line each)
- R1. (ANSWERED by the owner: no private sponsors repository.) There is no private mirror and no sponsors-only early access; the KDE and macOS histories become public with the push. Remaining one-line question: confirm the push itself at L3 (KDE has 0 stars, 0 forks, one author; irreversible once pushed).
- R2. May the macOS artefact ship in the 0.2.0 RELEASE before the 5-hour hand-check? (It does not gate the dev-line landing.) Recommendation: no; release Windows and Linux first, macOS as a pre-release after you run blocks 0 to 4 at least; keep
komorebi-for-macun-archived until then. - R3. Where do the Linux and macOS docs publish? The Windows site excludes them (
exclude_docs). Recommendation: the Starlight site (komorebi-starlight) for all three, GitHub Pagesgh-pagesstays Windows-only until it is ready. - R4. Are the known failures release blockers? Recommendation: not blockers; re-mark the four stale e2e markers and the two
fullscreenchecks before the first nightly, ship with the lock-hold stall andfullscreenlisted in the notes. - R5. (DECIDED by the owner: per-platform schema files, and NO root
schema*.jsoncopies and no freshness test.) Consequence in 2.2b. Open sub-question, only needed at the release: the published file names per platform. Recommendation:komorebi.<platform>.<version>.schema.jsonandkomorebi.bar.<platform>.<version>.schema.json(platform =windows,linux,macos; no bar file for linux) on the existing Cloudflare Pages project, withkomorebi-for-mac.lgug2z.comkept alive for the 0.1.x names; and for in-repo$schemalines use the tagged raw URLhttps://raw.githubusercontent.com/LGUG2Z/komorebi/v0.2.0/schemas/<platform>/schema.json(tags are immutable). - R6. (DECIDED by the owner: one sponsor-only
[FEAT]policy for all three platforms, one licence.) The policy and the licence stay; the texts must be rewritten so they make sense for one public project with no private tier. The concrete task list is in 2.2a. One-line question left: who rewrites the texts, and by when (before CI goes on at L4, because the auto-close workflow acts on the first feature issue). - R7. N for the old macOS repository and the name of the Homebrew formula. Recommendation: 3 months, formula name unchanged for 0.2.0.
- R8. Freeze and PRs. Recommendation: freeze
masternow, merge the ready PRs, comment the path map on the rest, close the 8 dependabot PRs. - R9. CI hosting. Hosted Linux/macOS plus your own machine for Windows e2e (needs the evaluation ISO that expires every 90 days). Recommendation: yes; Windows e2e stays off fork PRs.
- R10. Keep
hotfix/*andfeature/*push triggers? Recommendation: drop them, PR-only. - R11. nixpkgs
komorebi. Someone must updatepackage.nixfor the new tree after 0.2.0; recommendation: you send the bump yourself or ask the maintainer. - R12. Cache. Recommendation: GitHub cache with per-platform keys first, Cachix only if PR time exceeds 30 minutes.
What could not be determined: active user counts, the macOS repo's 13 "open issues", the cost of hosted minutes, the hosted-runner wall time of the KDE suites, why the KDE ci push runs fail in 7 to 10 seconds, whether Chocolatey or other third-party packages exist, the role of PAT and SCOOP_TOKEN, DNS for komorebi.lgug2z.com and komorebi-for-mac.lgug2z.com, nixpkgs' build of the new tree, the real names of the flake outputs (placeholders until flake-one lands), whether the 19 community PRs merge cleanly after the renames, the installed jj version.
Appendix A. Drafts of the workflow files (text only; nothing was created under .github/)
Placeholders: FLAKE_* (see the head of this document). Pin actions by tag as the old files did (actions/checkout@v7, actions/upload-artifact@v7, actions/download-artifact@v8, versions as in the old workflows and in the dependabot PRs open on the Windows repository).
A.1 .github/workflows/ci.yaml
name: ci
on:
pull_request:
push:
branches: [master]
schedule:
- cron: "30 0 * * *" # nightly: the sweeps and the prerelease
workflow_dispatch:
concurrency:
group: ci-${{ github.event_name == 'pull_request' && github.ref || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
deny:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: EmbarkStudios/cargo-deny-action@v2
# The old KDE job: every check that boots no VM, as a derivation, in shards so that one runner does not run
# out of resources. FLAKE_CHECKS_* are the check attribute names of the root flake (placeholders).
nix-checks:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- shard: windows
pattern: "^(windows|win)-" # FLAKE_CHECKS_windows
- shard: linux
pattern: "^(linux|kde|kfde)-.*(clippy|nextest|fmt|doc|deny|schema|nix-options|module)"
- shard: rest
pattern: ""
steps:
- uses: actions/checkout@v7
with: { fetch-depth: 0 }
- uses: ./.github/actions/nix
- env:
PATTERN: ${{ matrix.pattern }}
run: |
nix eval --json .#checks.x86_64-linux --apply builtins.attrNames |
jq -r --arg p "$PATTERN" '.[] | select(startswith("vm-") | not) | select(if $p == "" then true else test($p) end)' |
sed 's|^|.#checks.x86_64-linux.|' | xargs --no-run-if-empty nix build -L --no-link
windows-build:
strategy:
fail-fast: true
matrix:
platform:
- { os-name: Windows-x86_64, runs-on: windows-latest, target: x86_64-pc-windows-msvc }
- { os-name: Windows-aarch64, runs-on: windows-latest, target: aarch64-pc-windows-msvc }
runs-on: ${{ matrix.platform.runs-on }}
env:
RUSTFLAGS: -Ctarget-feature=+crt-static -Dwarnings
steps:
- uses: actions/checkout@v7
with: { fetch-depth: 0 }
- run: rustup toolchain install stable --profile minimal
- run: rustup component add --toolchain stable-x86_64-pc-windows-msvc clippy
- run: rustup toolchain install nightly --allow-downgrade -c rustfmt
- uses: Swatinem/rust-cache@v2
with: { cache-on-failure: "true", cache-all-crates: "true", key: "${{ matrix.platform.target }}" }
- name: Check that no file is stored with CRLF
run: |
$crlf = git ls-files --eol | Select-String -Pattern '^i/crlf'
if ($crlf) { $crlf; exit 1 }
- run: cargo +nightly fmt --check
- run: cargo clippy --locked
- run: cargo test --locked
- uses: houseabsolute/actions-rust-cross@v1
with: { command: build, target: "${{ matrix.platform.target }}", args: "--locked --release" }
- run: |
cargo install cargo-wix
cargo wix --no-build -p komorebi --nocapture -I .\wix\main.wxs --target ${{ matrix.platform.target }}
- uses: actions/upload-artifact@v7
with:
name: komorebi-${{ matrix.platform.target }}-${{ github.sha }}
path: |
target/${{ matrix.platform.target }}/release/*.exe
target/${{ matrix.platform.target }}/release/*.pdb
target/wix/komorebi-*.msi
retention-days: 14
macos-build:
runs-on: macos-14 # or [self-hosted, macos, arm64]: decide with R9
steps:
- uses: actions/checkout@v7
with: { fetch-depth: 0 }
- uses: ./.github/actions/nix
- run: |
nix build -L .#FLAKE_MACOS_PKGS # placeholder: komorebi, komorebic, komorebi-bar
nix build -L .#checks.aarch64-darwin.FLAKE_CHECKS_macos
- uses: actions/upload-artifact@v7
with:
name: komorebi-aarch64-apple-darwin-${{ github.sha }}
path: result/bin/komorebi*
retention-days: 14
discover:
runs-on: ubuntu-24.04
outputs:
fast: ${{ steps.tiers.outputs.fast }}
slow: ${{ steps.tiers.outputs.slow }}
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/nix
- id: tiers
run: |
tiers=$(nix eval --json .#legacyPackages.x86_64-linux.FLAKE_VM_TIERS)
echo "fast=$(jq -c '.fast // []' <<<"$tiers")" >> "$GITHUB_OUTPUT"
echo "slow=$(jq -c '.slow // []' <<<"$tiers")" >> "$GITHUB_OUTPUT"
vm-fast:
needs: discover
# fork PRs run no VM (no KVM guarantee, and a fork edits the workflow)
if: needs.discover.outputs.fast != '[]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
runs-on: ubuntu-24.04
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
suite: ${{ fromJson(needs.discover.outputs.fast) }}
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/nix
with: { kvm: "true" }
- run: nix build -L .#checks.x86_64-linux.vm-${{ matrix.suite }}
vm-slow:
needs: discover
if: >-
needs.discover.outputs.slow != '[]' &&
(github.ref == 'refs/heads/master' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' ||
contains(github.event.pull_request.labels.*.name, 'ci:vm-slow'))
runs-on: ubuntu-24.04
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
suite: ${{ fromJson(needs.discover.outputs.slow) }}
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/nix
with: { kvm: "true" }
- run: nix build -L .#legacyPackages.x86_64-linux.vm.${{ matrix.suite }}.driver -o driver
- run: mkdir -p out && cd out && ../driver/bin/nixos-test-driver -o .
- if: always()
uses: actions/upload-artifact@v7
with: { name: "vm-${{ matrix.suite }}-${{ github.sha }}", path: out/, retention-days: 7 }
linux-build:
strategy:
fail-fast: false
matrix:
include:
- { target: x86_64-unknown-linux-gnu, runs-on: ubuntu-24.04, loader: /lib64/ld-linux-x86-64.so.2, optional: false }
- { target: aarch64-unknown-linux-gnu, runs-on: ubuntu-24.04-arm, loader: /lib/ld-linux-aarch64.so.1, optional: true }
runs-on: ${{ matrix.runs-on }}
continue-on-error: ${{ matrix.optional }}
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/nix
- env: { LOADER: "${{ matrix.loader }}" }
run: |
mkdir bin
for name in komorebi komorebic; do
cp "$(nix build -L --no-link --print-out-paths ".#FLAKE_LINUX_PKGS_$name")/bin/$name" bin/ # placeholder attribute per binary
done
chmod u+w bin/*
nix run --inputs-from . nixpkgs#patchelf -- --set-interpreter "$LOADER" --remove-rpath bin/*
bin/komorebi --version
bin/komorebic --version
- uses: actions/upload-artifact@v7
with: { name: "komorebi-${{ matrix.target }}-${{ github.sha }}", path: bin/, retention-days: 14 }
# The one required check (branch ruleset names only this job).
required:
if: always()
needs: [deny, nix-checks, windows-build, macos-build, vm-fast, linux-build]
runs-on: ubuntu-24.04
steps:
- run: |
echo '${{ toJSON(needs) }}' | jq -e 'to_entries | all(.value.result == "success" or .value.result == "skipped")'
A.2 .github/workflows/e2e.yaml (the Windows e2e on the owner's host)
name: e2e-windows
on:
schedule:
- cron: "15 1 * * *" # nightly: the 22 scenarios; the full set on Sundays
pull_request:
types: [labeled, synchronize]
workflow_dispatch:
inputs:
scenarios:
description: "space separated scenarios, or 'full'"
default: "commands"
permissions:
contents: read
jobs:
e2e:
# label-gated and never for fork code: the runner is the owner's machine
if: >-
github.event_name != 'pull_request' ||
(contains(github.event.pull_request.labels.*.name, 'ci:e2e') &&
github.event.pull_request.head.repo.full_name == github.repository)
runs-on: [self-hosted, linux, kvm-windows-e2e]
timeout-minutes: 240
steps:
- uses: actions/checkout@v7
with: { fetch-depth: 0 }
- name: Does this diff owe an e2e? (PR only)
if: github.event_name == 'pull_request'
run: tools/e2e-needed --range || true
- name: Run
env:
E2E_GOLDEN: /srv/komorebi-e2e/golden # built once, see e2e/platforms/qemu_windows/README.md
run: |
set -eu
nightly="commands workspaces focus stacks monocle floating maximizing rules rules_class rules_exe manage_rules startup_rules title_rule layouts config_reload lifecycle handover resize lifecycle_hidden hotplug promoting"
case "${{ github.event_name }}:${{ inputs.scenarios }}" in
schedule:*) if [ "$(date +%u)" = 7 ]; then set -- ; else set -- $nightly; fi ;; # no arguments = the full set (check the runner's CLI)
workflow_dispatch:full) set -- ;;
workflow_dispatch:*) set -- ${{ inputs.scenarios }} ;;
*) set -- commands ;;
esac
nix run .#FLAKE_E2E_WINDOWS -- "$RUNNER_TEMP/out" "$@"
- if: always()
uses: actions/upload-artifact@v7
with: { name: e2e-${{ github.run_id }}, path: "${{ runner.temp }}/out/**/result.json", retention-days: 14 }
Whether e2e-windows with no scenario names runs the full set is not verified (its usage line says e2e-windows OUT SCENARIO..., flake.nix:456): list the 47 names, or add an all word, before using it.
A.3 .github/workflows/release.yaml (RELEASE phase: leave this file out of the dev-line landing, or keep only the ci call; the schedule and v* triggers and the nightly publish must not fire until the release phase)
name: release
on:
push:
tags: ["v*"]
schedule:
- cron: "30 0 * * 0" # the weekly nightly, as before
workflow_dispatch:
permissions:
contents: read
jobs:
ci:
uses: ./.github/workflows/ci.yaml # needs `on: workflow_call` added to ci.yaml
publish:
needs: ci
runs-on: ubuntu-24.04
permissions:
contents: write
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
steps:
- uses: actions/checkout@v7
with: { fetch-depth: 0 }
- run: |
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
echo "TAG=$GITHUB_REF_NAME" >>"$GITHUB_ENV"; echo "VERSION=${GITHUB_REF_NAME#v}" >>"$GITHUB_ENV"
else
echo "TAG=nightly" >>"$GITHUB_ENV"; echo "VERSION=nightly" >>"$GITHUB_ENV"
fi
- uses: actions/download-artifact@v8
with: { pattern: "komorebi-*-${{ github.sha }}", path: artifacts }
- name: Package (Windows zips and MSIs, Linux zips, macOS zip) with the names Scoop and WinGet expect
shell: bash
run: |
mkdir dist
for t in x86_64-pc-windows-msvc aarch64-pc-windows-msvc; do
d="artifacts/komorebi-$t-$GITHUB_SHA"
(cd "$d/$t/release" && zip -j "$GITHUB_WORKSPACE/dist/komorebi-$VERSION-$t.zip" *.exe)
cp "$d"/wix/*"${t%%-*}".msi "dist/komorebi-$VERSION-${t%%-*}.msi"
done
for t in x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; do
d="artifacts/komorebi-$t-$GITHUB_SHA"; [ -d "$d" ] || continue
chmod +x "$d"/*; zip -j "dist/komorebi-$VERSION-$t.zip" "$d"/komorebi "$d"/komorebic
done
d="artifacts/komorebi-aarch64-apple-darwin-$GITHUB_SHA"
chmod +x "$d"/*; zip -j "dist/komorebi-$VERSION-aarch64-apple-darwin.zip" "$d"/*
cp schemas/windows/schema.json dist/schema.windows.json
cp schemas/linux/schema.json dist/schema.linux.json
cp schemas/macos/schema.json dist/schema.macos.json
(cd dist && sha256sum -- *.zip *.msi *.json > checksums.txt)
- name: Release notes
run: |
if [ "$TAG" = nightly ]; then
cargo install --locked kokai@0.3.1
git tag --force nightly
kokai release --no-emoji --add-links github:commits,issues --ref nightly >"$RUNNER_TEMP/notes.md"
else
cp docs/dev/RELEASE-NOTES-$VERSION.md "$RUNNER_TEMP/notes.md" # written by hand (CUTOVER-PLAN 4.5)
fi
- name: Publish
run: |
if [ "$TAG" = nightly ]; then
gh release delete nightly --cleanup-tag --yes || true
gh release create nightly --target "$GITHUB_SHA" --prerelease --title "komorebi nightly ($GITHUB_SHA)" \
--notes-file "$RUNNER_TEMP/notes.md" dist/*
else
gh release create "$TAG" --verify-tag --draft --title "komorebi $TAG" --notes-file "$RUNNER_TEMP/notes.md" dist/*
# the owner reviews the draft and publishes it by hand; WinGet runs on publish
fi
winget:
needs: publish
if: github.event_name == 'release' && github.event.action == 'published' # moved to its own workflow `on: release: published` when drafts are used
runs-on: ubuntu-latest
steps:
- uses: vedantmgoyal2009/winget-releaser@main
with:
identifier: LGUG2Z.komorebi
token: ${{ secrets.WINGET_TOKEN }}
The winget job as written never runs from this file: a draft published by hand fires release: published, so it belongs in its own workflow file with that trigger. The Homebrew push is a second job in that file, using a fine-grained token limited to LGUG2Z/homebrew-tap and a formula without the token header (the old formula.template.rb replaced REPLACE_ASSET_ID and REPLACE_SHA_256 with sed; keep that mechanism, replace url by the public download URL).
A.4 .github/workflows/update-flake-lock.yaml, rerun-no-kvm.yaml, canary.yaml
update-flake-lock.yaml and rerun-no-kvm.yaml: the old files unchanged (docs/dev/old-ci/linux/workflows/), with the if: github.repository == 'LGUG2Z/komorebi-for-kde' guards changed to LGUG2Z/komorebi, and workflows: [ci] kept in rerun-no-kvm. canary.yaml: the old canary job split by platform group, with the nixpkgs move done in a copy of the checkout as before (docs/dev/old-ci/linux/workflows/ci.yaml canary, 360-minute timeout) and the issue title "Canary: a check fails against the tip of nixpkgs-unstable" kept so the existing issue logic keeps working.
A.5 .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule: { interval: "weekly" }
assignees: ["LGUG2Z"]
commit-message: { prefix: chore, include: scope }
- package-ecosystem: "cargo"
directory: "/"
schedule: { interval: "weekly" }
assignees: ["LGUG2Z"]
commit-message: { prefix: chore, include: scope }
groups:
cargo-minor-patch:
update-types: ["minor", "patch"]
# flake.lock is updated by .github/workflows/update-flake-lock.yaml (weekly); the `nix` ecosystem is not enabled
# so that two bots do not update the same file.
A.6 .github/actions/nix/action.yaml
The old composite action (docs/dev/old-ci/linux/actions/nix/action.yaml) moves as is to .github/actions/nix/action.yaml; its cache key hashFiles('flake.lock', '**/Cargo.lock') already covers the one lock; add the runner's job group to the key prefix for the cache decision R12.
Appendix B. Where the facts come from
docs/dev/MIGRATION-SUMMARY.md (sections 1, 4-7, 9), docs/dev/known-issues.md, docs/dev/unified-binaries.md, docs/dev/build-and-test.md (sections 1-6), docs/dev/macos-hand-check-plan.md (headers, line 288), docs/macos/README.md:43-47, .github/workflows/*, docs/dev/old-ci/{linux,macos}/**, Cargo.toml:61, justfile (schemapub, windows_targets), wix/main.wxs, mkdocs.yml, e2e/platforms/qemu_windows/README.md, tools/e2e-needed; the plan generic-percolating-matsumoto.md ("Decisions already made", Part A); the progress log ~/.claude/plans/komomono-progress.md (the entries for the e2e gates, "ALL GATES GREEN on wip-cand9b", the cutover cleanup and docs-paths entries) and the decisions log; commands: jj log -r ... on /home/jado/komomono-work/komorebi, git log/grep/show/blame/tag on that clone and on the three old clones, gh repo view, gh api (repos, branches, rulesets, pages, secrets (names), actions/runs, releases, contents of ScoopInstaller/Extras and NixOS/nixpkgs and LGUG2Z/homebrew-tap), gh issue list, gh pr list, gh release list, gh workflow list, and one curl -I to https://komorebi.lgug2z.com/komorebi.0.1.41.schema.json (404).