Skip to content

feat: ship vfkit as #1 macOS engine with Lima parity - #55

Merged
enegalan merged 1 commit into
mainfrom
feat/vfkit-number-one
Jul 19, 2026
Merged

feat: ship vfkit as #1 macOS engine with Lima parity#55
enegalan merged 1 commit into
mainfrom
feat/vfkit-number-one

Conversation

@enegalan

@enegalan enegalan commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • vfkit gains buildx, host.docker.internal, localhost IPv6 proxies, guest HTTP proxy apply, and Rosetta on by default on Apple silicon
  • Primary BENCHMARKS.md table now shows vfkit numbers (Calf leads or ties OrbStack on the reference Mac); Lima moved to legacy
  • Version bump to 0.9.6

Test plan

  • CI backend + ui green
  • macOS: auto vfkit start; docker buildx version; host.docker.internal from a container
  • Published ports reachable via IPv6 localhost
  • After merge: release workflow; upload guest disk asset if CI guest job fails
  • Homebrew cask bump after DMG publishes

Made with Cursor

Summary by CodeRabbit

  • New Features

    • macOS now prefers the vfkit engine when available, with Lima remaining as an alternative.
    • Improved localhost port forwarding, host.docker.internal access, BuildKit/buildx support, and Rosetta configuration on Apple Silicon.
    • Added runtime start support and more reliable VM restart and keep-alive behavior.
  • Documentation

    • Updated benchmarks, roadmap, release notes, and setup guidance to reflect vfkit as the primary macOS engine.
  • Release

    • Updated the application and desktop app version to 0.9.6.

Close buildx, host.docker.internal, localhost proxies, and proxy apply on
vfkit; promote vfkit numbers to the primary benchmark table.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR makes vfkit the default macOS runtime, expands vfkit lifecycle, guest networking, proxy, Rosetta, and build behavior, updates guest provisioning and benchmark documentation, and releases version 0.9.6.

Changes

vfkit default runtime

Layer / File(s) Summary
Runtime selection and vfkit state
backend/internal/runtime/select_darwin.go, backend/internal/runtime/vfkit_darwin.go
Explicit and automatically ready vfkit paths construct Vfkit, whose state now tracks lifecycle ownership and localhost proxy synchronization.
Lifecycle, guest integration, and build behavior
backend/internal/runtime/vfkit_darwin.go
Startup and shutdown coordinate background watchers, buildx, guest networking, proxy forwarding, keep-alive behavior, and Rosetta; builds fall back to Docker when buildx is unavailable.
Guest DNS and host mapping
scripts/guest-image/lima-vfkit.yaml
Guest provisioning installs dnsmasq, configures Docker DNS, and maps host.docker.internal through the Docker bridge gateway.
Default engine and benchmark documentation
BENCHMARKS.md, ROADMAP.md, docs/phase5-race.md
Documentation promotes vfkit benchmarks and default behavior while retaining Lima as a legacy or escape-hatch runtime.
0.9.6 release metadata
backend/version/version.go, ui/pubspec.yaml, CHANGELOG.md
Backend and UI versions become 0.9.6, and the changelog records the vfkit and runtime-start changes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Runtime as Vfkit runtime
  participant Guest as Guest Docker daemon
  participant Proxy as Localhost proxy
  Runtime->>Guest: Start guest and initialize runtime
  Runtime->>Guest: Check Docker API and configure guest networking
  Runtime->>Proxy: Apply configured proxy and start resync watcher
  Guest-->>Runtime: Return status and published container ports
  Runtime->>Proxy: Synchronize localhost forwarding
Loading

Possibly related PRs

  • enegalan/calf#53: Earlier experimental vfkit runtime work in the same macOS runtime selection and implementation files.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: vfkit becomes the primary macOS engine with Lima parity.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/vfkit-number-one

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@enegalan
enegalan merged commit 24c1bf7 into main Jul 19, 2026
2 of 3 checks passed
@enegalan
enegalan deleted the feat/vfkit-number-one branch July 19, 2026 14:34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
backend/internal/runtime/vfkit_darwin.go (1)

427-444: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Mutex unlocked manually instead of via defer.

v.mu.Lock()/v.mu.Unlock() here are not paired with defer, unlike SetOwnerContext/resetLifecycle elsewhere in this file. Same pattern also appears in ApplyProxy (Line 605-607). As per coding guidelines, "Release acquired resources with defer immediately after acquisition, including files, mutexes, and cancellation functions."

🔧 Suggested fix
 	v.mu.Lock()
+	defer v.mu.Unlock()
 	if v.watcherCancel != nil {
 		v.watcherCancel()
 		v.watcherCancel = nil
 	}
-	v.mu.Unlock()
 	v.localhostProxy.stopAll()
🤖 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 427 - 444, Update Stop
and ApplyProxy to defer v.mu.Unlock() immediately after acquiring v.mu.Lock(),
removing the manual unlock calls while preserving the existing critical-section
behavior.

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/runtime/vfkit_darwin.go`:
- Around line 555-570: Update the proxyResync handling in Vfkit.ListContainers
to replace the separate Load and Store operations with an atomic
CompareAndSwap(true, false), while preserving the existing forced localhost
proxy synchronization behavior.
- Around line 310-336: Extract the duplicated background setup from both Start
branches into a shared startBackgroundServices helper, and invoke it from the
already-running and freshly-launched paths. Within the helper, read v.proxy
under v.mu into a local value before checking or passing it to ApplyProxy, while
preserving the existing lifecycle context, goroutines, state stores, and watcher
startup behavior.
- Around line 268-294: Replace the check-then-clear handling of the proxyResync
flag in watchPortProxies and the corresponding ListContainers flow with atomic
CompareAndSwap(true, false). Only clear the flag after the resync succeeds and
the compare-and-swap confirms it was still true, preserving any concurrent
request that sets it back to true.
- Around line 373-379: Update the enableRosetta override in the Rosetta
configuration block so CALF_VFKIT_ROSETTA=1 can only enable Rosetta when
goruntime.GOARCH is arm64. Preserve the existing default behavior and
CALF_VFKIT_ROSETTA=0 disable behavior on arm64.
- Around line 178-192: Update guestCommandRunner’s sudo handling to preserve the
bash -c script boundary when ensureBuildx passes sudo bash -c with its script
argument. Special-case that argv shape or quote each argument before
constructing the runGuestRoot command, while preserving existing behavior for
other sudo invocations.

In `@CHANGELOG.md`:
- Around line 14-18: Revise the vfkit feature-parity changelog entry to describe
only user-visible capabilities, removing implementation details such as dnsmasq,
gateway refresh, and guest terminology, plus the ::1 protocol notation. Revise
the public benchmarks entry to describe the updated benchmark presentation
without naming BENCHMARKS.md, while preserving the user-facing performance
result and Lima comparison.

---

Nitpick comments:
In `@backend/internal/runtime/vfkit_darwin.go`:
- Around line 427-444: Update Stop and ApplyProxy to defer v.mu.Unlock()
immediately after acquiring v.mu.Lock(), removing the manual unlock calls while
preserving the existing critical-section behavior.
🪄 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: bb09a6ab-d028-413a-ac3d-048bbdd3f95f

📥 Commits

Reviewing files that changed from the base of the PR and between 30b03a7 and 284d405.

📒 Files selected for processing (9)
  • BENCHMARKS.md
  • CHANGELOG.md
  • ROADMAP.md
  • backend/internal/runtime/select_darwin.go
  • backend/internal/runtime/vfkit_darwin.go
  • backend/version/version.go
  • docs/phase5-race.md
  • scripts/guest-image/lima-vfkit.yaml
  • ui/pubspec.yaml

Comment on lines +178 to +192
// guestCommandRunner adapts guest root shells and docker CLI for shared helpers (proxy, buildx install).
func (v *Vfkit) guestCommandRunner(ctx context.Context, command string, args ...string) ([]byte, error) {
if command == "nerdctl" || command == "docker" {
return v.runLocal(ctx, command, args...)
}
if command == "bash" && len(args) >= 2 && args[0] == "-lc" {
return v.runGuestRoot(ctx, args[1])
}
if command == "sudo" && len(args) >= 1 {
joined := strings.Join(args, " ")
return v.runGuestRoot(ctx, joined)
}
all := append([]string{command}, args...)
return v.runGuestRoot(ctx, strings.Join(all, " "))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect ensureBuildx's call pattern into the commandRunner to verify argument shapes.
rg -n -A15 'func ensureBuildx' backend/internal/runtime

Repository: enegalan/calf

Length of output: 1515


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the runtime helpers around guestCommandRunner and runGuestRoot.
sed -n '1,260p' backend/internal/runtime/vfkit_darwin.go

printf '\n--- buildx.go ---\n'
sed -n '1,120p' backend/internal/runtime/buildx.go

printf '\n--- proxy.go ---\n'
sed -n '1,220p' backend/internal/runtime/proxy.go

Repository: enegalan/calf

Length of output: 12931


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find all commandRunner call sites to see whether the sudo/default branches
# receive arguments containing whitespace or shell metacharacters.
rg -n 'run\([^)]*"sudo"|run\([^)]*"bash"|run\([^)]*"docker"|run\([^)]*"nerdctl"' backend/internal/runtime

Repository: enegalan/calf

Length of output: 5310


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the shell-quoting helper and any runGuestRoot implementation details.
rg -n 'shellQuote|runGuestRoot|guestCommandRunner' backend/internal/runtime

Repository: enegalan/calf

Length of output: 1715


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the exact helper implementations and all commandRunner call sites.
sed -n '1,260p' backend/internal/runtime/vfkit_darwin.go
printf '\n--- buildx.go ---\n'
sed -n '1,120p' backend/internal/runtime/buildx.go
printf '\n--- proxy.go ---\n'
sed -n '1,220p' backend/internal/runtime/proxy.go

printf '\n--- commandRunner call sites ---\n'
rg -n -A2 -B2 'run\(ctx, "sudo"|run\(ctx, "bash"|run\(ctx, "docker"|run\(ctx, "nerdctl"' backend/internal/runtime

Repository: enegalan/calf

Length of output: 30047


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the implementation and usages of runGuestRoot and shellQuote directly.
rg -n -A6 -B6 'func \(v \*Vfkit\) runGuestRoot|shellQuote\(' backend/internal/runtime

Repository: enegalan/calf

Length of output: 3641


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the exact vfkit helper implementations around the adapter.
sed -n '170,250p' backend/internal/runtime/vfkit_darwin.go

Repository: enegalan/calf

Length of output: 2975


Quote the sudo command before re-entering the shell
ensureBuildx passes sudo bash -c "DEBIAN_FRONTEND=... && ...", but guestCommandRunner flattens args with strings.Join and then feeds them to bash -lc, so the bash -c script boundary is lost. Preserve argv boundaries here—either special-case sudo bash -c or quote each arg before joining.

🤖 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 178 - 192, Update
guestCommandRunner’s sudo handling to preserve the bash -c script boundary when
ensureBuildx passes sudo bash -c with its script argument. Special-case that
argv shape or quote each argument before constructing the runGuestRoot command,
while preserving existing behavior for other sudo invocations.

Comment on lines +268 to +294
// watchPortProxies periodically resyncs localhost proxies with published container ports.
func (v *Vfkit) watchPortProxies(ctx context.Context) {
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
status, err := v.Status(ctx)
if err != nil || status.State != State(constants.RuntimeStateRunning) || !v.started.Load() {
continue
}
containers, err := listContainers(ctx, v.runLocal)
if err != nil {
v.proxyResync.Store(true)
continue
}
force := v.proxyResync.Load()
v.localhostProxy.sync(publishedTCPPorts(containers), force)
if force {
v.proxyResync.Store(false)
}
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Lost-update race on proxyResync flag.

force := v.proxyResync.Load() followed later by v.proxyResync.Store(false) is a check-then-act sequence. If another goroutine sets proxyResync back to true in between (e.g. a concurrent Start()/Status()), this resets it to false anyway, silently swallowing the new forced-resync request. The same pattern exists in ListContainers (Line 562-566) — same root cause, worth fixing together with atomic.Bool.CompareAndSwap(true, false).

🔧 Suggested fix
-			force := v.proxyResync.Load()
-			v.localhostProxy.sync(publishedTCPPorts(containers), force)
-			if force {
-				v.proxyResync.Store(false)
-			}
+			force := v.proxyResync.CompareAndSwap(true, false)
+			v.localhostProxy.sync(publishedTCPPorts(containers), force)
📝 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.

Suggested change
// watchPortProxies periodically resyncs localhost proxies with published container ports.
func (v *Vfkit) watchPortProxies(ctx context.Context) {
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
status, err := v.Status(ctx)
if err != nil || status.State != State(constants.RuntimeStateRunning) || !v.started.Load() {
continue
}
containers, err := listContainers(ctx, v.runLocal)
if err != nil {
v.proxyResync.Store(true)
continue
}
force := v.proxyResync.Load()
v.localhostProxy.sync(publishedTCPPorts(containers), force)
if force {
v.proxyResync.Store(false)
}
}
}
}
// watchPortProxies periodically resyncs localhost proxies with published container ports.
func (v *Vfkit) watchPortProxies(ctx context.Context) {
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
status, err := v.Status(ctx)
if err != nil || status.State != State(constants.RuntimeStateRunning) || !v.started.Load() {
continue
}
containers, err := listContainers(ctx, v.runLocal)
if err != nil {
v.proxyResync.Store(true)
continue
}
force := v.proxyResync.CompareAndSwap(true, false)
v.localhostProxy.sync(publishedTCPPorts(containers), force)
}
}
}
🤖 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 268 - 294, Replace the
check-then-clear handling of the proxyResync flag in watchPortProxies and the
corresponding ListContainers flow with atomic CompareAndSwap(true, false). Only
clear the flag after the resync succeeds and the compare-and-swap confirms it
was still true, preserving any concurrent request that sets it back to true.

Comment on lines +310 to +336
lifeCtx := v.resetLifecycle()
if v.dockerAPIReady(ctx) && v.processAlive() {
v.ensureHostMountSymlink(ctx)
v.ensureBuildxAsync(lifeCtx)
if os.Getenv("CALF_BENCHMARK") != "1" {
go func() {
setupCtx, cancel := context.WithTimeout(lifeCtx, constants.DefaultActionTimeout)
defer cancel()
v.ensureHostDockerInternal(setupCtx)
}()
}
if v.proxy != (ProxyConfig{}) {
proxy := v.proxy
go func() {
applyCtx, cancel := context.WithTimeout(lifeCtx, constants.DefaultActionTimeout)
defer cancel()
if err := v.ApplyProxy(applyCtx, proxy); err != nil {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return
}
vfkitLogger.Warn("proxy application during start failed (non-fatal)", "error", err)
}
}()
}
v.started.Store(true)
v.proxyResync.Store(true)
go v.watchPortProxies(lifeCtx)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Data race on v.proxy, plus duplicated background-setup block.

v.proxy != (ProxyConfig{}) and proxy := v.proxy are read here without holding v.mu, while ApplyProxy (Line 605-607) writes v.proxy under the lock. Two goroutines calling Start and ApplyProxy concurrently race on this field.

Separately, this entire background-setup sequence (host mount symlink, buildx bootstrap, host.docker.internal goroutine, proxy-apply goroutine, started/proxyResync stores, watcher start) is duplicated verbatim between the "already running" branch (310-336) and the "freshly launched" branch (399-424). Extracting a single helper would fix the race in one place and prevent the two paths from silently diverging in the future.

🔒 Suggested fix: extract a shared helper and lock the proxy read
+// startBackgroundServices kicks off buildx bootstrap, host.docker.internal setup,
+// and pending proxy application once the guest is confirmed reachable.
+func (v *Vfkit) startBackgroundServices(ctx, lifeCtx context.Context) {
+	v.ensureHostMountSymlink(ctx)
+	v.ensureBuildxAsync(lifeCtx)
+	if os.Getenv("CALF_BENCHMARK") != "1" {
+		go func() {
+			setupCtx, cancel := context.WithTimeout(lifeCtx, constants.DefaultActionTimeout)
+			defer cancel()
+			v.ensureHostDockerInternal(setupCtx)
+		}()
+	}
+	v.mu.Lock()
+	proxy := v.proxy
+	v.mu.Unlock()
+	if proxy != (ProxyConfig{}) {
+		go func() {
+			applyCtx, cancel := context.WithTimeout(lifeCtx, constants.DefaultActionTimeout)
+			defer cancel()
+			if err := v.ApplyProxy(applyCtx, proxy); err != nil {
+				if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
+					return
+				}
+				vfkitLogger.Warn("proxy application during start failed (non-fatal)", "error", err)
+			}
+		}()
+	}
+	v.started.Store(true)
+	v.proxyResync.Store(true)
+	go v.watchPortProxies(lifeCtx)
+}

Then call v.startBackgroundServices(ctx, lifeCtx) from both branches instead of duplicating the block.

Also applies to: 399-424

🤖 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 310 - 336, Extract the
duplicated background setup from both Start branches into a shared
startBackgroundServices helper, and invoke it from the already-running and
freshly-launched paths. Within the helper, read v.proxy under v.mu into a local
value before checking or passing it to ApplyProxy, while preserving the existing
lifecycle context, goroutines, state stores, and watcher startup behavior.

Comment on lines +373 to +379
// Rosetta on by default for arm64 (match Lima); disable with CALF_VFKIT_ROSETTA=0.
rosettaEnv := strings.TrimSpace(os.Getenv("CALF_VFKIT_ROSETTA"))
enableRosetta := goruntime.GOARCH == "arm64" && rosettaEnv != "0"
if rosettaEnv == "1" {
enableRosetta = true
}
if enableRosetta {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does vfkit support the rosetta virtio device on x86_64 hosts?

💡 Result:

No, vfkit does not support the Rosetta virtio device on x86_64 hosts [1][2]. Rosetta support in vfkit is specifically designed to run x86_64 binaries within Linux virtual machines on Apple Silicon (ARM64) hosts [1][3][2]. According to the official documentation and technical specifications for vfkit, the --device rosetta option is exclusive to machines with Apple CPUs [1]. If this option is used on an Intel-based (x86_64) machine, vfkit will fail with an error [1]. This functionality leverages Apple's Virtualization framework to provide cross-architecture execution, which is not applicable or supported on x86_64 hardware [1][4][5].

Citations:


Gate the Rosetta override on arm64

CALF_VFKIT_ROSETTA=1 should still respect the arm64 check; otherwise vfkit will try to add an unsupported Rosetta device on Intel hosts and fail to start.

Suggested fix
-	if rosettaEnv == "1" {
-		enableRosetta = true
-	}
+	if rosettaEnv == "1" && goruntime.GOARCH == "arm64" {
+		enableRosetta = true
+	}
📝 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.

Suggested change
// Rosetta on by default for arm64 (match Lima); disable with CALF_VFKIT_ROSETTA=0.
rosettaEnv := strings.TrimSpace(os.Getenv("CALF_VFKIT_ROSETTA"))
enableRosetta := goruntime.GOARCH == "arm64" && rosettaEnv != "0"
if rosettaEnv == "1" {
enableRosetta = true
}
if enableRosetta {
// Rosetta on by default for arm64 (match Lima); disable with CALF_VFKIT_ROSETTA=0.
rosettaEnv := strings.TrimSpace(os.Getenv("CALF_VFKIT_ROSETTA"))
enableRosetta := goruntime.GOARCH == "arm64" && rosettaEnv != "0"
if rosettaEnv == "1" && goruntime.GOARCH == "arm64" {
enableRosetta = true
}
if enableRosetta {
🤖 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 373 - 379, Update the
enableRosetta override in the Rosetta configuration block so
CALF_VFKIT_ROSETTA=1 can only enable Rosetta when goruntime.GOARCH is arm64.
Preserve the existing default behavior and CALF_VFKIT_ROSETTA=0 disable behavior
on arm64.

Comment on lines 555 to 570
func (v *Vfkit) ListContainers(ctx context.Context) ([]Container, error) {
return emptyIfStopped(ctx, v.Status, func(ctx context.Context) ([]Container, error) { return listContainers(ctx, v.runLocal) })
return emptyIfStopped(ctx, v.Status, func(ctx context.Context) ([]Container, error) {
if !v.started.Load() {
return []Container{}, nil
}
containers, err := listContainers(ctx, v.runLocal)
if err == nil {
force := v.proxyResync.Load()
v.localhostProxy.sync(publishedTCPPorts(containers), force)
if force {
v.proxyResync.Store(false)
}
}
return containers, err
})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Same proxyResync lost-update race as watchPortProxies.

Line 562-566 repeats the Load-then-Store pattern flagged at Line 268-294; same fix (CompareAndSwap(true, false)) applies here.

🤖 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 555 - 570, Update the
proxyResync handling in Vfkit.ListContainers to replace the separate Load and
Store operations with an atomic CompareAndSwap(true, false), while preserving
the existing forced localhost proxy synchronization behavior.

Comment thread CHANGELOG.md
Comment on lines +14 to +18
- **vfkit feature parity** — buildx builds, `host.docker.internal` (dnsmasq + gateway refresh), localhost `::1` port proxies, HTTP proxy apply inside the guest, and Rosetta on by default on Apple silicon (`CALF_VFKIT_ROSETTA=0` to disable).

### Changed

- **Public benchmarks** — the primary `BENCHMARKS.md` table now uses the vfkit engine (Calf leads or ties OrbStack on every metric on the reference Mac); Lima numbers move to a legacy section.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove implementation details, file paths, and protocol jargon from changelog entries.

The changelog entries include implementation details (dnsmasq + gateway refresh, inside the guest), protocol jargon (::1), and file paths (BENCHMARKS.md). As per coding guidelines, changelog entries must be written in user-facing terms, excluding these details.

Consider revising the entries to focus on the user-visible impact.

📝 Proposed fix
- - **vfkit feature parity** — buildx builds, `host.docker.internal` (dnsmasq + gateway refresh), localhost `::1` port proxies, HTTP proxy apply inside the guest, and Rosetta on by default on Apple silicon (`CALF_VFKIT_ROSETTA=0` to disable).
+ - **Fast-boot engine parity** — Added support for `docker buildx`, `host.docker.internal` resolution, IPv6 localhost port forwarding, HTTP proxy configuration, and enabled Apple Rosetta by default (`CALF_VFKIT_ROSETTA=0` to disable).
 
 ### Changed
 
- - **Public benchmarks** — the primary `BENCHMARKS.md` table now uses the vfkit engine (Calf leads or ties OrbStack on every metric on the reference Mac); Lima numbers move to a legacy section.
+ - **Public benchmarks** — the primary performance comparison now uses the fast-boot engine (Calf leads or ties OrbStack on every metric on the reference Mac); previous engine results are moved to a legacy section.
📝 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.

Suggested change
- **vfkit feature parity**buildx builds, `host.docker.internal` (dnsmasq + gateway refresh), localhost `::1` port proxies, HTTP proxy apply inside the guest, and Rosetta on by default on Apple silicon (`CALF_VFKIT_ROSETTA=0` to disable).
### Changed
- **Public benchmarks** — the primary `BENCHMARKS.md` table now uses the vfkit engine (Calf leads or ties OrbStack on every metric on the reference Mac); Lima numbers move to a legacy section.
- **Fast-boot engine parity**Added support for `docker buildx`, `host.docker.internal` resolution, IPv6 localhost port forwarding, HTTP proxy configuration, and enabled Apple Rosetta by default (`CALF_VFKIT_ROSETTA=0` to disable).
### Changed
- **Public benchmarks** — the primary performance comparison now uses the fast-boot engine (Calf leads or ties OrbStack on every metric on the reference Mac); previous engine results are moved to a legacy section.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~14-~14: Did you mean the proper noun “Apple Silicon”?
Context: ...the guest, and Rosetta on by default on Apple silicon (CALF_VFKIT_ROSETTA=0 to disable). #...

(APPLE_PRODUCTS)

🤖 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 14 - 18, Revise the vfkit feature-parity changelog
entry to describe only user-visible capabilities, removing implementation
details such as dnsmasq, gateway refresh, and guest terminology, plus the ::1
protocol notation. Revise the public benchmarks entry to describe the updated
benchmark presentation without naming BENCHMARKS.md, while preserving the
user-facing performance result and Lima comparison.

Source: Coding guidelines

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