feat: experimental vfkit fast-boot engine (v0.9.5) - #53
Conversation
Ship a direct VZ path that beats OrbStack on cold start and most public benchmarks, with auto-select when a guest disk (or bundled vfkit + release seed) is available, CI guest-disk assets, and v0.9.5. Co-authored-by: Cursor <cursoragent@cursor.com>
📝 WalkthroughWalkthroughThe PR adds an experimental macOS vfkit runtime, Darwin runtime selection, guest disk creation and download flows, a runtime start API, release packaging, benchmark integration, and updated project documentation and version metadata. ChangesRuntime entry points and selection
vfkit engine and guest disk
Guest image and release pipeline
vfkit benchmark orchestration
Documentation and release metadata
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant CalfDaemon
participant Vfkit
participant GuestDisk
participant Docker
User->>CalfDaemon: POST /v1/runtime/start
CalfDaemon->>Vfkit: Start runtime
Vfkit->>GuestDisk: Ensure or download disk
Vfkit->>Docker: Boot guest and poll /_ping
Docker-->>Vfkit: Ready
Vfkit-->>CalfDaemon: Runtime status
CalfDaemon-->>User: JSON status
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/internal/runtime/lima.go (1)
120-133: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick winBackground
limactl startgoroutine uses the request-scopedctx, not the already-availablelifeCtx— gets killed once the caller's timeout context is cancelled.
lifeCtx(line 120) exists precisely so that work started here can outlive thisStart()call (it's used forensureBuildxAsyncand the proxy-apply goroutine). ButstartVMUntilDockerReady(ctx)(line 130) passes the caller'sctxinstead.EnsureRuntimeRunning(backend/internal/daemon/runtime_ready.go) callss.Runtime.Start(startCtx)withstartCtx, cancel := context.WithTimeout(ctx, 3*time.Minute); defer cancel(). As soon asStart()returns success andEnsureRuntimeRunning's own polling loop seesRunning,cancel()fires — killing the still-in-flightlimactl startprocess (and the goroutine at lines 208-213 watching it) even though Docker became reachable beforelimactl startfully finished. This can abort VM provisioning mid-flight and spuriously flipsshellReadyback tofalse.🔧 Proposed fix: use `lifeCtx` for work that must survive the call
running, err := l.vmIsRunning(ctx) if err != nil { return err } if running { l.shellReady.Store(true) } else { - if err := l.startVMUntilDockerReady(ctx); err != nil { + if err := l.startVMUntilDockerReady(ctx, lifeCtx); err != nil { return err } }And inside
startVMUntilDockerReady, run the two background goroutines againstlifeCtxinstead ofctx(keepingctxfor the synchronousinstanceExists/createcalls and for theselect's<-ctx.Done()early-return), so cancelling the caller's short-lived context no longer kills the in-flightlimactl start.Also applies to: 160-216
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/internal/runtime/lima.go` around lines 120 - 133, Use the lifecycle context for VM startup work that must outlive Start: pass lifeCtx from Start into startVMUntilDockerReady, and use lifeCtx for both background goroutines that launch or monitor limactl start. Keep the request-scoped ctx for synchronous instanceExists/create operations and the select’s ctx.Done early return.
🧹 Nitpick comments (4)
scripts/benchmarks/_common.sh (1)
223-235: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract a shared "force-stop vfkit guest" helper. Both sites independently implement the same disable-autostart → kill-limactl → kill-vfkit-pid → pkill-vfkit → wait-for-exit sequence; any future change (e.g., an extra cleanup step) risks drifting between the two copies.
scripts/benchmarks/_common.sh#L223-L235: extract this sequence (lines 224-233) into a helper, e.g.force_stop_vfkit_calf, and call it here beforestop_calf_daemon.scripts/benchmarks/run-all.sh#L121-L152: call the sameforce_stop_vfkit_calfhelper (lines 129-137) instead of re-inlining the sequence, then keep therm -f docker.sock/wait_for_docker_host_downsteps that are specific to this call site.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/benchmarks/_common.sh` around lines 223 - 235, Extract the duplicated disable-autostart and force-stop sequence into a shared force_stop_vfkit_calf helper in scripts/benchmarks/_common.sh, and call it from the _common.sh cleanup site before stop_calf_daemon. In scripts/benchmarks/run-all.sh, replace the inlined sequence with the same helper while retaining the site-specific rm -f docker.sock and wait_for_docker_host_down steps..github/workflows/release.yml (1)
80-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated
vfkit-guestCI job body across two workflow files. The build/pack/upload steps for the guest disk asset are copy-pasted between the two files with no shared definition, so any future change (paths, artifact name, tool versions) risks drifting out of sync between them.
.github/workflows/release.yml#L80-L104: extract this job body into a reusable workflow (workflow_call) or composite action and have this job call it..github/workflows/vfkit-guest.yml#L16-L38: have this workflow call the same reusable workflow/action instead of duplicating the steps.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release.yml around lines 80 - 104, Extract the duplicated vfkit guest build, packaging, and upload steps into one reusable workflow or composite action. Update .github/workflows/release.yml lines 80-104 and .github/workflows/vfkit-guest.yml lines 16-38 so both vfkit-guest jobs invoke that shared definition, preserving the existing runner, tooling, artifact name, and asset paths.backend/internal/runtime/vfkit_disk_fetch_darwin.go (1)
118-144: 🔒 Security & Privacy | 🔵 Trivial | ⚖️ Poor tradeoffConsider verifying downloaded disk integrity.
downloadGuestDiskfetches a multi-GB guest disk over HTTPS and extracts it without any checksum/signature verification. A corrupted or truncated download that still returns HTTP 200 will be extracted and booted. If the release pipeline can publish a checksum asset, validate it afterdownloadFilebeforeextractGuestSeed.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/internal/runtime/vfkit_disk_fetch_darwin.go` around lines 118 - 144, The downloadGuestDisk flow currently accepts the guest disk without integrity validation. Add checksum or signature asset resolution and validate dest after downloadFile succeeds, before the disk reaches extractGuestSeed; return a descriptive error and reject or remove the artifact when verification fails, while preserving the existing optional EFI behavior.backend/internal/runtime/vfkit_darwin.go (1)
249-581: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd doc comments to exported and unexported methods/functions. Several new Go declarations have no immediately preceding
//doc comment, which the project requires. As per coding guidelines: "Add a doc comment to every function and method://immediately above Go declarations."
backend/internal/runtime/vfkit_darwin.go#L249-L581: documentstopProcess,processAlive,waitForDockerAPI,dockerAPIReady,runLocal,runLocalWithStdin, and the Runtime interface implementations (ListContainers,ListImages, …RegistryLogout).backend/internal/runtime/vfkit_disk_fetch_darwin.go#L170-L218: documentreleaseAssetURL,latestReleaseAssetURL,getJSON, anddownloadFile.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/internal/runtime/vfkit_darwin.go` around lines 249 - 581, Add immediately preceding Go doc comments for every listed declaration in backend/internal/runtime/vfkit_darwin.go lines 249-581: stopProcess, processAlive, waitForDockerAPI, dockerAPIReady, runLocal, runLocalWithStdin, and all Runtime implementations through RegistryLogout, using comments that describe each method’s behavior and begin with its declaration name. Also document releaseAssetURL, latestReleaseAssetURL, getJSON, and downloadFile in backend/internal/runtime/vfkit_disk_fetch_darwin.go lines 170-218; no other changes are needed.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/internal/api/runtime.go`:
- Around line 10-21: Update handleRuntimeStart to route both
EnsureRuntimeRunning and Runtime.Status errors through httpkit.WriteRuntimeError
instead of directly calling httpkit.WriteError with err.Error(), preserving the
existing early returns and successful status response.
In `@backend/internal/runtime/vfkit_darwin.go`:
- Line 389: Protect the shared proxy configuration with v.mu: update ApplyProxy
to lock while assigning v.proxy, and update runLocal to read/copy v.proxy under
the same mutex before constructing the environment. Preserve the existing proxy
behavior while ensuring all accesses use the shared lock.
In `@CHANGELOG.md`:
- Around line 8-21: Rewrite the 0.9.5 entries in CHANGELOG.md to describe
user-visible benefits only: fast startup on supported macOS systems and the
ability to start the container runtime while the daemon remains running. Remove
implementation details, library and binary names, artifact filenames, build
commands, documentation references, and HTTP endpoint/protocol terminology.
In `@scripts/benchmarks/_common.sh`:
- Around line 264-288: Remove the second duplicate definition of
enable_lima_autostart_calf, retaining the first implementation and its existing
behavior. Keep disable_lima_autostart_calf unchanged.
In `@scripts/guest-image/unpack-vfkit-disk.sh`:
- Around line 23-26: Update the EFI archive lookup in the unpack flow around
EFI_ZST so it supports the release asset naming pattern
calf-vfkit-efi-<arch>.zst alongside the existing efi-store.zst name. Mirror the
runtime extractGuestSeed lookup behavior, selecting an available sibling archive
before running the existing zstd extraction.
In `@ui/macos/Runner.xcodeproj/project.pbxproj`:
- Line 341: Ensure the macOS release workflow installs or exposes vfkit before
packaging so the Xcode shellScript can bundle it. Update
.github/workflows/release.yml lines 21-25 and 66-68 to install vfkit with
Homebrew or set CALF_VFKIT_BIN; ui/macos/Runner.xcodeproj/project.pbxproj lines
341-341 requires no direct change because its existing lookup and copy logic
will then include the binary.
---
Outside diff comments:
In `@backend/internal/runtime/lima.go`:
- Around line 120-133: Use the lifecycle context for VM startup work that must
outlive Start: pass lifeCtx from Start into startVMUntilDockerReady, and use
lifeCtx for both background goroutines that launch or monitor limactl start.
Keep the request-scoped ctx for synchronous instanceExists/create operations and
the select’s ctx.Done early return.
---
Nitpick comments:
In @.github/workflows/release.yml:
- Around line 80-104: Extract the duplicated vfkit guest build, packaging, and
upload steps into one reusable workflow or composite action. Update
.github/workflows/release.yml lines 80-104 and .github/workflows/vfkit-guest.yml
lines 16-38 so both vfkit-guest jobs invoke that shared definition, preserving
the existing runner, tooling, artifact name, and asset paths.
In `@backend/internal/runtime/vfkit_darwin.go`:
- Around line 249-581: Add immediately preceding Go doc comments for every
listed declaration in backend/internal/runtime/vfkit_darwin.go lines 249-581:
stopProcess, processAlive, waitForDockerAPI, dockerAPIReady, runLocal,
runLocalWithStdin, and all Runtime implementations through RegistryLogout, using
comments that describe each method’s behavior and begin with its declaration
name. Also document releaseAssetURL, latestReleaseAssetURL, getJSON, and
downloadFile in backend/internal/runtime/vfkit_disk_fetch_darwin.go lines
170-218; no other changes are needed.
In `@backend/internal/runtime/vfkit_disk_fetch_darwin.go`:
- Around line 118-144: The downloadGuestDisk flow currently accepts the guest
disk without integrity validation. Add checksum or signature asset resolution
and validate dest after downloadFile succeeds, before the disk reaches
extractGuestSeed; return a descriptive error and reject or remove the artifact
when verification fails, while preserving the existing optional EFI behavior.
In `@scripts/benchmarks/_common.sh`:
- Around line 223-235: Extract the duplicated disable-autostart and force-stop
sequence into a shared force_stop_vfkit_calf helper in
scripts/benchmarks/_common.sh, and call it from the _common.sh cleanup site
before stop_calf_daemon. In scripts/benchmarks/run-all.sh, replace the inlined
sequence with the same helper while retaining the site-specific rm -f
docker.sock and wait_for_docker_host_down steps.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 204a85a4-97b0-4558-8bae-74b670dc13bd
⛔ Files ignored due to path filters (1)
backend/go.sumis excluded by!**/*.sum
📒 Files selected for processing (31)
.cursor/rules/calf.mdc.github/workflows/release.yml.github/workflows/vfkit-guest.ymlBENCHMARKS.mdCHANGELOG.mdCLAUDE.mdMakefileROADMAP.mdbackend/go.modbackend/internal/api/gateway.gobackend/internal/api/runtime.gobackend/internal/constants/constants.gobackend/internal/runtime/lima.gobackend/internal/runtime/lima.yamlbackend/internal/runtime/runtime.gobackend/internal/runtime/select_darwin.gobackend/internal/runtime/select_other.gobackend/internal/runtime/vfkit_darwin.gobackend/internal/runtime/vfkit_disk_fetch_darwin.gobackend/test/runtime/vfkit_disk_zstd_test.gobackend/version/version.godocs/phase5-race.mdscripts/benchmarks/_common.shscripts/benchmarks/run-all.shscripts/guest-image/build-vfkit-guest.shscripts/guest-image/lima-vfkit.yamlscripts/guest-image/pack-vfkit-disk.shscripts/guest-image/prepare-vfkit-disk.shscripts/guest-image/unpack-vfkit-disk.shui/macos/Runner.xcodeproj/project.pbxprojui/pubspec.yaml
| func (g *Gateway) handleRuntimeStart(w http.ResponseWriter, r *http.Request) { | ||
| if err := g.backend.EnsureRuntimeRunning(r.Context()); err != nil { | ||
| httpkit.WriteError(w, http.StatusServiceUnavailable, err.Error()) | ||
| return | ||
| } | ||
| status, err := g.backend.Runtime.Status(r.Context()) | ||
| if err != nil { | ||
| httpkit.WriteError(w, http.StatusInternalServerError, err.Error()) | ||
| return | ||
| } | ||
| httpkit.WriteJSON(w, http.StatusOK, status) | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether writeRuntimeError exists and how other handlers report runtime errors.
rg -n -A5 -B2 'func writeRuntimeError' backend/internal/api backend/internal/httpkit
rg -n 'writeRuntimeError\(' backend/internal/api
rg -n -A3 'func WriteError' backend/internal/httpkitRepository: enegalan/calf
Length of output: 442
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== runtime.go ==\n'
cat -n backend/internal/api/runtime.go
printf '\n== api error helpers/search ==\n'
rg -n -A3 -B3 'writeRuntimeError|WriteError\(|WriteJSON\(' backend/internal/api backend/internal/httpkit
printf '\n== httpkit response helper ==\n'
cat -n backend/internal/httpkit/response.goRepository: enegalan/calf
Length of output: 41523
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== runtime-related symbols ==\n'
rg -n 'EnsureRuntimeRunning|Runtime\.Status|handleRuntimeStart|handleRuntime' backend/internal/api backend/internal -g '!**/*_test.go'
printf '\n== line counts for relevant files ==\n'
wc -l backend/internal/api/runtime.go backend/internal/httpkit/response.goRepository: enegalan/calf
Length of output: 2719
Route runtime errors through httpkit.WriteRuntimeError here.
Both failures currently send err.Error() back to the client, which can leak wrapped internal details like Runtime.Status: .... httpkit.WriteRuntimeError already maps the runtime cases to safe HTTP responses.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@backend/internal/api/runtime.go` around lines 10 - 21, Update
handleRuntimeStart to route both EnsureRuntimeRunning and Runtime.Status errors
through httpkit.WriteRuntimeError instead of directly calling httpkit.WriteError
with err.Error(), preserving the existing early returns and successful status
response.
Source: Coding guidelines
| } | ||
| return removeNetwork(ctx, v.runLocal, name) | ||
| } | ||
| func (v *Vfkit) ApplyProxy(ctx context.Context, proxy ProxyConfig) error { v.proxy = proxy; return nil } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Guard v.proxy with the mutex to avoid a data race.
ApplyProxy writes v.proxy with no lock, while runLocal (Line 339) reads v.proxy on request-handler goroutines. Concurrent Docker operations and a proxy update produce a data race / torn read on the ProxyConfig struct. v.cmd is already guarded by v.mu; do the same for v.proxy.
🔒️ Proposed fix
-func (v *Vfkit) ApplyProxy(ctx context.Context, proxy ProxyConfig) error { v.proxy = proxy; return nil }
+func (v *Vfkit) ApplyProxy(ctx context.Context, proxy ProxyConfig) error {
+ v.mu.Lock()
+ v.proxy = proxy
+ v.mu.Unlock()
+ return nil
+}runLocal should read the field under the same lock before building the env.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func (v *Vfkit) ApplyProxy(ctx context.Context, proxy ProxyConfig) error { v.proxy = proxy; return nil } | |
| func (v *Vfkit) ApplyProxy(ctx context.Context, proxy ProxyConfig) error { | |
| v.mu.Lock() | |
| v.proxy = proxy | |
| v.mu.Unlock() | |
| return nil | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@backend/internal/runtime/vfkit_darwin.go` at line 389, Protect the shared
proxy configuration with v.mu: update ApplyProxy to lock while assigning
v.proxy, and update runLocal to read/copy v.proxy under the same mutex before
constructing the environment. Preserve the existing proxy behavior while
ensuring all accesses use the shared lock.
| ## [Unreleased] | ||
|
|
||
| ## [0.9.5] - 2026-07-19 | ||
|
|
||
| ### Added | ||
|
|
||
| - **Experimental fast-boot engine (macOS)** — when a provisioned vfkit guest disk (or release seed) and `vfkit` binary are present, Calf prefers that engine automatically; bundled apps download `calf-vfkit-disk-<arch>.raw.zst` from GitHub Releases on first start; build locally with `make guest-vfkit` (see `BENCHMARKS.md` and `docs/phase5-race.md`). | ||
| - **Runtime start API** — `POST /v1/runtime/start` boots the container runtime while the daemon stays up (used for fair VM-boot benches on vfkit). | ||
|
|
||
| ### Changed | ||
|
|
||
| - **Lima startup** — the Docker API can become ready before Lima finishes its SSH/boot-script gates, so the engine is usable sooner after a full VM stop. | ||
|
|
||
| ## [0.9.4] - 2026-07-18 |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Rewrite changelog entries to omit implementation details, file paths, and protocol jargon.
The current entries for version 0.9.5 contain implementation specifics (e.g., calf-vfkit-disk-<arch>.raw.zst, make guest-vfkit, BENCHMARKS.md, docs/phase5-race.md, and the POST /v1/runtime/start endpoint). As per coding guidelines, CHANGELOG.md entries must be written in user-facing terms, without implementation details, library names, file paths, or protocol jargon.
📝 Proposed fix
## [0.9.5] - 2026-07-19
### Added
-- **Experimental fast-boot engine (macOS)** — when a provisioned vfkit guest disk (or release seed) and `vfkit` binary are present, Calf prefers that engine automatically; bundled apps download `calf-vfkit-disk-<arch>.raw.zst` from GitHub Releases on first start; build locally with `make guest-vfkit` (see `BENCHMARKS.md` and `docs/phase5-race.md`).
-- **Runtime start API** — `POST /v1/runtime/start` boots the container runtime while the daemon stays up (used for fair VM-boot benches on vfkit).
+- **Experimental fast-boot engine (macOS)** — a new, significantly faster container engine is available on macOS and is selected automatically when prerequisites are met. The application will fetch the required components on first start.
+- **Runtime start API** — added an endpoint to start the container engine while the application daemon remains running, improving benchmark workflows.
### Changed📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## [Unreleased] | |
| ## [0.9.5] - 2026-07-19 | |
| ### Added | |
| - **Experimental fast-boot engine (macOS)** — when a provisioned vfkit guest disk (or release seed) and `vfkit` binary are present, Calf prefers that engine automatically; bundled apps download `calf-vfkit-disk-<arch>.raw.zst` from GitHub Releases on first start; build locally with `make guest-vfkit` (see `BENCHMARKS.md` and `docs/phase5-race.md`). | |
| - **Runtime start API** — `POST /v1/runtime/start` boots the container runtime while the daemon stays up (used for fair VM-boot benches on vfkit). | |
| ### Changed | |
| - **Lima startup** — the Docker API can become ready before Lima finishes its SSH/boot-script gates, so the engine is usable sooner after a full VM stop. | |
| ## [0.9.4] - 2026-07-18 | |
| ## [Unreleased] | |
| ## [0.9.5] - 2026-07-19 | |
| ### Added | |
| - **Experimental fast-boot engine (macOS)** — a new, significantly faster container engine is available on macOS and is selected automatically when prerequisites are met. The application will fetch the required components on first start. | |
| - **Runtime start API** — added an endpoint to start the container engine while the application daemon remains running, improving benchmark workflows. | |
| ### Changed | |
| - **Lima startup** — the Docker API can become ready before Lima finishes its SSH/boot-script gates, so the engine is usable sooner after a full VM stop. | |
| ## [0.9.4] - 2026-07-18 |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CHANGELOG.md` around lines 8 - 21, Rewrite the 0.9.5 entries in CHANGELOG.md
to describe user-visible benefits only: fast startup on supported macOS systems
and the ability to start the container runtime while the daemon remains running.
Remove implementation details, library and binary names, artifact filenames,
build commands, documentation references, and HTTP endpoint/protocol
terminology.
Source: Coding guidelines
| # disable_lima_autostart_calf unloads the Lima start-at-login agent for the Calf VM. | ||
| disable_lima_autostart_calf() { | ||
| local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist" | ||
| if [[ -f "$plist" ]]; then | ||
| launchctl bootout "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true | ||
| fi | ||
| } | ||
|
|
||
| # enable_lima_autostart_calf restores the Lima start-at-login agent if the plist exists. | ||
| enable_lima_autostart_calf() { | ||
| local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist" | ||
| if [[ -f "$plist" ]]; then | ||
| launchctl bootstrap "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true | ||
| fi | ||
| } | ||
|
|
||
|
|
||
| # enable_lima_autostart_calf restores the Lima start-at-login agent if the plist exists. | ||
| enable_lima_autostart_calf() { | ||
| local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist" | ||
| if [[ -f "$plist" ]]; then | ||
| launchctl bootstrap "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true | ||
| fi | ||
| } | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
enable_lima_autostart_calf is defined twice.
The block defines enable_lima_autostart_calf at lines 273-278 and again identically at 281-288. Shellcheck flags the first definition as unreachable/never invoked (SC2329), since the second silently shadows it. Remove the duplicate.
🧹 Proposed fix to remove the duplicate definition
# enable_lima_autostart_calf restores the Lima start-at-login agent if the plist exists.
enable_lima_autostart_calf() {
local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist"
if [[ -f "$plist" ]]; then
launchctl bootstrap "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true
fi
}
-
-
-# enable_lima_autostart_calf restores the Lima start-at-login agent if the plist exists.
-enable_lima_autostart_calf() {
- local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist"
- if [[ -f "$plist" ]]; then
- launchctl bootstrap "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true
- fi
-}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # disable_lima_autostart_calf unloads the Lima start-at-login agent for the Calf VM. | |
| disable_lima_autostart_calf() { | |
| local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist" | |
| if [[ -f "$plist" ]]; then | |
| launchctl bootout "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true | |
| fi | |
| } | |
| # enable_lima_autostart_calf restores the Lima start-at-login agent if the plist exists. | |
| enable_lima_autostart_calf() { | |
| local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist" | |
| if [[ -f "$plist" ]]; then | |
| launchctl bootstrap "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true | |
| fi | |
| } | |
| # enable_lima_autostart_calf restores the Lima start-at-login agent if the plist exists. | |
| enable_lima_autostart_calf() { | |
| local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist" | |
| if [[ -f "$plist" ]]; then | |
| launchctl bootstrap "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true | |
| fi | |
| } | |
| # disable_lima_autostart_calf unloads the Lima start-at-login agent for the Calf VM. | |
| disable_lima_autostart_calf() { | |
| local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist" | |
| if [[ -f "$plist" ]]; then | |
| launchctl bootout "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true | |
| fi | |
| } | |
| # enable_lima_autostart_calf restores the Lima start-at-login agent if the plist exists. | |
| enable_lima_autostart_calf() { | |
| local plist="${HOME}/Library/LaunchAgents/io.lima-vm.autostart.${CALF_VM_NAME}.plist" | |
| if [[ -f "$plist" ]]; then | |
| launchctl bootstrap "gui/$(id -u)" "$plist" >/dev/null 2>&1 || true | |
| fi | |
| } |
🧰 Tools
🪛 Shellcheck (0.11.0)
[info] 273-278: This function is never invoked. Check usage (or ignored if invoked indirectly).
(SC2329)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/benchmarks/_common.sh` around lines 264 - 288, Remove the second
duplicate definition of enable_lima_autostart_calf, retaining the first
implementation and its existing behavior. Keep disable_lima_autostart_calf
unchanged.
Source: Linters/SAST tools
| EFI_ZST="$(dirname "$ARCHIVE")/efi-store.zst" | ||
| if [[ -f "$EFI_ZST" ]]; then | ||
| zstd -f -d -o "${DEST_DIR}/efi-store" "$EFI_ZST" | ||
| fi |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
EFI lookup only matches efi-store.zst, not the release asset name.
When users unpack a GitHub Release disk asset (calf-vfkit-disk-<arch>.raw.zst), its EFI sibling is named calf-vfkit-efi-<arch>.zst, but this script only probes efi-store.zst, so the EFI store is silently skipped. The runtime's extractGuestSeed handles both naming schemes; mirror that here.
🔧 Proposed fix
-EFI_ZST="$(dirname "$ARCHIVE")/efi-store.zst"
-if [[ -f "$EFI_ZST" ]]; then
- zstd -f -d -o "${DEST_DIR}/efi-store" "$EFI_ZST"
-fi
+EFI_ZST="$(dirname "$ARCHIVE")/efi-store.zst"
+# Release assets name the EFI store per-arch, e.g. calf-vfkit-efi-arm64.zst.
+if [[ ! -f "$EFI_ZST" ]]; then
+ EFI_ZST="$(echo "$ARCHIVE" | sed 's/calf-vfkit-disk-\(.*\)\.raw\.zst/calf-vfkit-efi-\1.zst/')"
+fi
+if [[ -f "$EFI_ZST" ]]; then
+ zstd -f -d -o "${DEST_DIR}/efi-store" "$EFI_ZST"
+fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| EFI_ZST="$(dirname "$ARCHIVE")/efi-store.zst" | |
| if [[ -f "$EFI_ZST" ]]; then | |
| zstd -f -d -o "${DEST_DIR}/efi-store" "$EFI_ZST" | |
| fi | |
| EFI_ZST="$(dirname "$ARCHIVE")/efi-store.zst" | |
| # Release assets name the EFI store per-arch, e.g. calf-vfkit-efi-arm64.zst. | |
| if [[ ! -f "$EFI_ZST" ]]; then | |
| EFI_ZST="$(echo "$ARCHIVE" | sed 's/calf-vfkit-disk-\(.*\)\.raw\.zst/calf-vfkit-efi-\1.zst/')" | |
| fi | |
| if [[ -f "$EFI_ZST" ]]; then | |
| zstd -f -d -o "${DEST_DIR}/efi-store" "$EFI_ZST" | |
| fi |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/guest-image/unpack-vfkit-disk.sh` around lines 23 - 26, Update the
EFI archive lookup in the unpack flow around EFI_ZST so it supports the release
asset naming pattern calf-vfkit-efi-<arch>.zst alongside the existing
efi-store.zst name. Mirror the runtime extractGuestSeed lookup behavior,
selecting an available sibling archive before running the existing zstd
extraction.
| runOnlyForDeploymentPostprocessing = 0; | ||
| shellPath = /bin/sh; | ||
| shellScript = "set -eu\nDEST_DIR=\"$TARGET_BUILD_DIR/$FULL_PRODUCT_NAME/Contents/MacOS\"\nmkdir -p \"$DEST_DIR\"\n(cd \"$PROJECT_DIR/../../backend\" && CGO_ENABLED=0 go build -o \"$DEST_DIR/calf-daemon\" ./cmd/calf)\nchmod +x \"$DEST_DIR/calf-daemon\"\nif command -v codesign >/dev/null 2>&1; then codesign --force --sign - --identifier com.enegalan.calf.daemon \"$DEST_DIR/calf-daemon\" 2>/dev/null || true; fi\n"; | ||
| shellScript = "set -eu\nDEST_DIR=\"$TARGET_BUILD_DIR/$FULL_PRODUCT_NAME/Contents/MacOS\"\nmkdir -p \"$DEST_DIR\"\n(cd \"$PROJECT_DIR/../../backend\" && CGO_ENABLED=0 go build -o \"$DEST_DIR/calf-daemon\" ./cmd/calf)\nchmod +x \"$DEST_DIR/calf-daemon\"\nif command -v codesign >/dev/null 2>&1; then codesign --force --sign - --identifier com.enegalan.calf.daemon \"$DEST_DIR/calf-daemon\" 2>/dev/null || true; fi\nVFKIT_SRC=\"${CALF_VFKIT_BIN:-}\"\nif [ -z \"$VFKIT_SRC\" ] && command -v vfkit >/dev/null 2>&1; then VFKIT_SRC=\"$(command -v vfkit)\"; fi\nif [ -n \"$VFKIT_SRC\" ] && [ -x \"$VFKIT_SRC\" ]; then\n cp \"$VFKIT_SRC\" \"$DEST_DIR/vfkit\"\n chmod +x \"$DEST_DIR/vfkit\"\n if command -v codesign >/dev/null 2>&1; then codesign --force --sign - --identifier com.enegalan.calf.vfkit \"$DEST_DIR/vfkit\" 2>/dev/null || true; fi\nfi\n"; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== vfkit references ==\n'
rg -n --hidden --glob '!**/.git/**' 'vfkit|CALF_VFKIT_BIN|vfkitReady\(' .
printf '\n== release workflow excerpt ==\n'
sed -n '1,140p' .github/workflows/release.yml
printf '\n== macOS Xcode build phase excerpt ==\n'
sed -n '300,380p' ui/macos/Runner.xcodeproj/project.pbxprojRepository: enegalan/calf
Length of output: 29522
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Makefile macOS packaging target ==\n'
sed -n '60,95p' Makefile
printf '\n== release-macos / package-macos definitions ==\n'
rg -n '^release-macos:|^package-macos:|VFKIT_SRC|vfkit' Makefile
printf '\n== any workflow mention of vfkit install in release path ==\n'
rg -n 'brew install vfkit|CALF_VFKIT_BIN|release-macos|package-macos' .github/workflows Makefile docs BENCHMARKS.md ROADMAP.md CHANGELOG.mdRepository: enegalan/calf
Length of output: 4677
🌐 Web query:
GitHub Actions macOS runner vfkit preinstalled macos-latest
💡 Result:
GitHub-hosted macOS runners do not officially support nested virtualization, and as a result, they do not provide a preinstalled, supported environment for running tools like vfkit or other hypervisors [1][2][3]. While the command-line tool vfkit—which utilizes Apple's Virtualization framework—is often available for installation via Homebrew on GitHub-hosted macOS runners (or may be included in certain runner environment configurations), attempting to run it typically results in failure because the underlying runner environment does not permit nested virtualization [1][4][2]. Key points regarding this limitation: 1. No Nested Virtualization Support: GitHub Actions documentation explicitly states that nested virtualization is not supported on macOS runners [2]. This applies to both Intel and Apple Silicon (Arm64) architectures [1][2][5]. 2. Environment Constraints: GitHub-hosted runners themselves run on virtual machines, and the limitations of Apple's Virtualization framework (used by the hosting infrastructure) generally prevent users from spawning additional VMs or hypervisors inside the runner [1][6]. 3. vfkit Issues: Users attempting to use tools like Podman Machine or other software that relies on vfkit often report that it exits unexpectedly or throws "virtualization is not enabled" errors [1][4][5]. 4. Alternative Options: Because of these limitations, developers requiring native virtualization support are often directed to use bare-metal runners rather than GitHub-hosted virtualized runners [1]. As of July 19, 2026, the current macOS images (such as macOS 26 "Tahoe") maintain these same restrictions, regardless of the macOS version [7][4].
Citations:
- 1: Running podman inside github actions macosx runner. podman-container-tools/podman#26859
- 2: https://docs.github.com/en/actions/reference/runners/larger-runners
- 3: QEMU hang on macos-15-intel starting with 15.7.1 actions/runner-images#13277
- 4: CI: vfkit broken on macos tahoe runners podman-container-tools/podman#27873
- 5: Virtualization is not enabled error on macos13 M1 runner actions/runner-images#8465
- 6: https://josephduffy.co.uk/posts/self-hosting-macos-github-runners
- 7: https://github.com/actions/runner-images/blob/main/images/macos/macos-26-Readme.md
Bundle vfkit during macOS packaging
.github/workflows/release.yml only installs create-dmg before make package-macos, but Makefile only embeds vfkit when it is on PATH or CALF_VFKIT_BIN is set. Add brew install vfkit (or export CALF_VFKIT_BIN) in the macOS release job so the shipped .dmg/.pkg includes the bundled binary.
📍 Affects 2 files
ui/macos/Runner.xcodeproj/project.pbxproj#L341-L341(this comment).github/workflows/release.yml#L21-L25.github/workflows/release.yml#L66-L68
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ui/macos/Runner.xcodeproj/project.pbxproj` at line 341, Ensure the macOS
release workflow installs or exposes vfkit before packaging so the Xcode
shellScript can bundle it. Update .github/workflows/release.yml lines 21-25 and
66-68 to install vfkit with Homebrew or set CALF_VFKIT_BIN;
ui/macos/Runner.xcodeproj/project.pbxproj lines 341-341 requires no direct
change because its existing lookup and copy logic will then include the binary.
Summary
vfkitruntime (virtio-vsock Docker) with auto-select when a guest disk exists or vfkit is bundled next to the daemoncalf-vfkit-disk-<arch>.raw.zstfrom GitHub Releases; CI builds the guest asset on releaseTest plan
v0.9.5includingcalf-vfkit-disk-*.raw.zstmake guest-vfkitthenmake benchmarks-vfkitMade with Cursor
Summary by CodeRabbit
New Features
POST /v1/runtime/start.Bug Fixes
Documentation