Skip to content

Reinstall over an existing Omarchy in its own space - #46

Open
joshuaswarren wants to merge 2 commits into
omacom:mainfrom
joshuaswarren:fix/reinstall-reuses-existing-space
Open

joshuaswarren wants to merge 2 commits into
omacom:mainfrom
joshuaswarren:fix/reinstall-reuses-existing-space

Conversation

@joshuaswarren

Copy link
Copy Markdown
Contributor

This PR lets someone who already has Omarchy on their Mac reinstall it over itself, instead of removing it and installing again. It reverses part of b1dade4 ("the installer never replaces an existing Omarchy"), so it needs the owner's call. @maralcbr, do you want this? The other half of b1dade4 stays: two or more installs still get the refusal.

The reason is time on a big disk. Today a reinstall means Remove Omarchy, which grows macOS back, and then a new install, which shrinks macOS by the same amount. On a 14-inch M2 Max with a 4 TB disk, that shrink is one diskutil apfs resizeContainer call. It took 2,740 s on 2026-10-06 and 5,002 s on 2026-09-18, both for the same 255,999,344,640 bytes. The engine's replace path deletes the old stub and erases the four partitions instead. That took about 14 s on the same Mac.

What changes:

  • On the refusal page, a Mac with exactly one found install now gets Reinstall Omarchy. It plans the engine's existing replace candidate, so the new install reuses the old install's space and macOS is not resized.
  • InstallerAllocationRecommendation(replacing:in:) picks the replace candidate at its exact length. preparePlan takes replacing:; without it an existing install is refused as before.
  • The session offers reinstallOverExisting() only for exactly one found install, and forgets the choice on the next inspection.
  • The plan page shows macOS at its current size and asks to approve the layout, not a resize.
  • The engine is unchanged.

The second commit is part of this PR, and it must ship with the first. Removal sets macOS as the startup disk before it deletes anything (eed259e), but the engine's remove_existing_install does not. Without the second commit, a reinstall started from macOS while Omarchy is still the startup disk would erase that Omarchy, and a failure after the erase would leave the Mac pointed at a volume that no longer boots. The helper now runs the same step before a replace install starts the engine. If bless refuses, or macOS does not confirm the change, the helper throws ClosedEngineHelperError.macOSStartupNotSet and nothing is erased. A fresh install never touches the startup disk. One thing I did not check: whether the new install sets Omarchy as the startup disk again at the end. If it does not, someone who wants Omarchy as the default sets it once in Startup Disk settings.

Tests: testReplacingPlansTheExistingInstallsExactExtent, testReinstallPlansTheReplaceOfTheOneExistingInstall, testReinstallIsUnavailableUnlessExactlyOneInstallWasFound and testAReplaceMakesMacOSTheStartupDiskBeforeTheEngineRuns (five cases). On main, the first three do not compile, because the reinstall API does not exist. With only the three-line call in submit removed, three of the five startup-disk cases fail, because the engine ran while the startup disk was still Omarchy. The existing refusal tests and the 64 OmarchyRemovalTests still pass.

Checked at b41100a, rebased on main 27bdf16 (no new commits upstream), on a Mac Studio with macOS 26.6.2, Xcode 27.0 and Swift 6.4:

  • swift-format lint --strict: exit 0.
  • Debug swift test: exit 0 (UXCore 149, Lifecycle 3, TrustCore 521 with the 1 existing skip, App 8).
  • Release swift test: exit 0 (138, 3, 521, 5).
  • ./test/all: exit 0.

Not done: no replace install has run on hardware, and there is no screenshot of the new refusal page. The engine's REPLACE_STAGES (remove_existing_install, journaled existing-install-removed) ship today but have not run from this app. The replace erases the old install's four partitions and its stub, so plan review, approval and the owner's password still come first, and only exactly one found install unlocks the button.

To revert, revert both commits. The app goes back to the b1dade4 refusal, and the engine is unchanged, so nothing on disk depends on the app change.

joshuaswarren and others added 2 commits October 8, 2026 18:27
Reinstalling meant Remove Omarchy, which grows macOS back over the old
partitions, then a new install, which shrinks macOS again by the same
amount. On a 14-inch M2 Max (4 TB, about 3.5 TB used by macOS) that
shrink was one `diskutil apfs resizeContainer` call of 2,740 s on
2026-10-06 and 5,002 s on 2026-09-18, both for the same 255,999,344,640
bytes at the same offset.

The engine already plans and runs a replace: it deletes the old stub and
erases the install's partitions (REPLACE_STAGES, journaled and never
replayed), then installs into that extent with no resize. On the same Mac
the delete and erases took about 14 s. Since b1dade4 the app refused an
existing install and left that path unused.

The refusal page now offers Reinstall Omarchy when the inspection found
exactly one install. It plans the engine's replace candidate at its exact
length; the plan still goes through review, approval and the owner's
password. A new inspection forgets the choice, so a normal install still
never replaces anything, and two or more installs keep the refusal. The
plan page shows macOS at its current size and asks to approve the layout,
not a resize.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A reinstall deletes the old Omarchy stub, which the Mac may start up
from. Removal already makes the running macOS the startup disk and the
next restart's choice, and confirms both, before it deletes anything
(eed259e). The engine's replace path did not, so a Mac set to start
Omarchy pointed at a deleted volume until the Recovery step.

The helper now runs the same step for an install whose plan is a
replace, before the engine starts. It skips the step when macOS is
already the startup disk, and refuses with macOSStartupNotSet when
bless refuses or macOS does not confirm the change; then nothing is
erased. The app explains that and points to Startup Disk settings. A
fresh install never touches the startup disk.

The step is now one function that removal and the helper share, and the
imported handoff package exposes its plan's candidate kind, which the
importer already checks against the plan digest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@joshuaswarren
joshuaswarren force-pushed the fix/reinstall-reuses-existing-space branch from b41100a to e90ad4d Compare October 8, 2026 23:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant