Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions .cursor/rules/calf.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Calf is a lightweight, open-source alternative to Docker Desktop:
- `backend/` — Go daemon managing containers via `containerd`/`nerdctl`, inside a Lima VM (macOS/Windows) or natively (Linux). Exposes a Docker-API-compatible socket (`~/.config/calf/docker.sock`) plus a REST + WebSocket API on `127.0.0.1:8765`.
- `ui/` — native Flutter GUI that drives the daemon over that API.

The Go daemon binary is embedded inside the Flutter `.app` bundle (`Contents/MacOS/calf-daemon`). When the app launches, it spawns the daemon as a subprocess and kills it on close. No separate installation or terminal setup required.

The real `docker` / `docker compose` CLI can point at Calf via `DOCKER_HOST`.

Non-goals: no built-in Kubernetes, no extensions marketplace, no Scout/AI/Cloud features (see `ROADMAP.md`).
Expand Down Expand Up @@ -51,7 +53,7 @@ Non-goals: no built-in Kubernetes, no extensions marketplace, no Scout/AI/Cloud
calf/
├── backend/ Go daemon
│ ├── cmd/calf/
│ │ └── main.go Entrypoint: config/logger/runtime/server wiring, signal handling, PID file, stale-port takeover
│ │ └── main.go Entrypoint: config/logger/runtime/server wiring, signal handling, PID file, stale-port takeover (cross-platform: lsof/Unix, netstat/Windows)
│ ├── internal/
│ │ ├── api/
│ │ │ ├── server.go Server struct, route registration for all /v1/... endpoints
Expand Down Expand Up @@ -110,7 +112,7 @@ calf/
│ └── go.mod / go.sum Module github.com/enegalan/calf/backend, Go 1.22.1
├── ui/ Flutter application
│ ├── lib/
│ │ ├── main.dart App entrypoint; Material theme bridged from ShadThemeData (light/dark)
│ │ ├── main.dart App entrypoint. Calls `_startDaemon()` to spawn the Go daemon binary (found next to the Flutter executable — `.app` bundle on macOS, alongside the binary on Linux/Windows) and waits for `/v1/status` to respond before showing the UI. Kills the daemon on app close. Inserts common Homebrew paths into `PATH` on macOS (no-op on other platforms). Builds a Material `ThemeData` bridged from a `ShadThemeData` (shadcn_ui), with a hardcoded brand primary color (`#2496ED`). Light/dark `ShadThemeData` instances are built once as top-level finals.
│ │ ├── app_shell.dart Sidebar nav, top bar, SettingsScreen (resources, migration, theme)
│ │ ├── api/
│ │ │ └── client.dart CalfClient/StatusClient interfaces + ApiClient (http + WebSocket)
Expand Down Expand Up @@ -144,7 +146,7 @@ calf/
│ └── .dockerignore
├── scripts/verify-docker-cli.sh Verifies `docker` CLI works against Calf's socket
├── .github/workflows/ci.yml CI: backend (vet/test/build) + ui (analyze/test/build) jobs, macos-latest
├── Makefile dev-backend / dev-ui / ui / clean / verify-docker-cli targets
├── Makefile dev-backend / dev-ui-macos / dev-ui-linux / dev-ui-windows / ui-macos / ui-linux / ui-windows / clean / verify-docker-cli / release / release-macos / release-linux / release-windows targets
├── README.md Project pitch + quick start
├── DEVELOPMENT.md Dev setup, config file example, Docker Desktop migration walkthrough
├── ROADMAP.md Phased plan, architecture diagram, non-goals, competitor comparison
Expand Down Expand Up @@ -252,10 +254,18 @@ Simple JSON files under `~/.config/calf/ui/<name>.json` (via `path_provider`'s a

```
make dev-backend # cd backend && CGO_ENABLED=0 go run ./cmd/calf
make dev-ui # flutter run -d macos
make ui # flutter build macos (alias: make build)
make clean # flutter clean
make verify-docker-cli # runs scripts/verify-docker-cli.sh
make dev-ui-macos # flutter run -d macos
make dev-ui-linux # flutter run -d linux
make dev-ui-windows # flutter run -d windows
make ui-macos # flutter build macos
make ui-linux # flutter build linux
make ui-windows # flutter build windows
make release # build Go daemon + Flutter app for all platforms
make release-macos # build Go daemon + macOS .app
make release-linux # build Go daemon + Linux bundle
make release-windows # build Go daemon + Windows bundle
make clean # flutter clean
make verify-docker-cli # runs scripts/verify-docker-cli.sh
```

CI (`.github/workflows/ci.yml`, both jobs on `macos-latest`):
Expand Down Expand Up @@ -284,4 +294,4 @@ CI (`.github/workflows/ci.yml`, both jobs on `macos-latest`):
## Before making changes

- Check `ROADMAP.md` before adding scope — respect the explicit non-goals.
- Run `make dev-backend` / `make dev-ui` to exercise changes locally.
- Run `make dev-backend` / `make dev-ui-macos` (or `make dev-ui-linux` / `make dev-ui-windows`) to exercise changes locally.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ jobs:
working-directory: backend
- run: CGO_ENABLED=0 go build -o /dev/null ./cmd/calf
working-directory: backend
- name: Cross-compile for Linux
run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /dev/null ./cmd/calf
working-directory: backend
- name: Cross-compile for Windows
run: CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o /dev/null ./cmd/calf
working-directory: backend

ui:
runs-on: macos-latest
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
.DS_Store
.vscode

# Binaries
backend/calf
backend/calf-daemon
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.0] - 2026-07-08

### Added

- **Cross-platform support** — Calf now runs on Linux, macOS, and Windows.
- **Automated cross-platform builds** verified in CI for Linux and Windows.
- **Windows port conflict cleanup** — stale daemon instances are detected and removed on Windows.
- **Linux build target** — `make ui-linux` and `make release-linux` are available.
- **Windows build target** — `make ui-windows` and `make release-windows` are available.
- **`docker compose` no longer hangs** — compose commands finish reliably.

### Changed

- Port conflict cleanup works across operating systems.
- PATH setup on macOS prefers Homebrew paths while leaving other systems unchanged.
- Links and URLs open with the platform handler on all supported systems.
- The bundled daemon binary is discovered next to the app executable on all platforms.
- Startup socket checks log missing sockets at Debug level instead of Warn.
- macOS release entitlements tightened: removed unsafe memory and library-validation exceptions. The app sandbox remains off so the backend can run required external tools.

### Fixed

- Container list parsing handles both structured and comma-separated labels.
- Streaming log and interactive exec commands consistently route through the VM runtime.
- macOS release build produces a single daemon binary that works on both Intel and Apple Silicon Macs, and signs it correctly so the app can launch the backend.
- UI startup spinner clears transient daemon errors once the runtime reaches the running state and no longer pretends the app is ready after the timeout expires.

## [0.6.0] - 2026-07-06

### Changed
Expand Down
24 changes: 17 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ This file provides guidance to AI assistants when working with code in this repo
- A **Go daemon** (`backend/`) that manages containers through `containerd` + `nerdctl`, running inside a **Lima** VM on macOS/Windows, or talking directly to the host runtime on Linux.
- A **native Flutter GUI** (`ui/`) that drives the daemon over a local REST + WebSocket API.

The Go daemon binary is embedded inside the Flutter `.app` bundle (`Contents/MacOS/calf-daemon`). When the app launches, it spawns the daemon as a subprocess and kills it on close. No separate installation or terminal setup required.

The daemon also exposes a Docker-API-compatible socket (`~/.config/calf/docker.sock`), so the real `docker` / `docker compose` CLI can point at Calf via `DOCKER_HOST`.

Non-goals (see `ROADMAP.md`): no built-in Kubernetes, no extensions marketplace, no Scout/AI/Cloud features.
Expand Down Expand Up @@ -49,7 +51,7 @@ Non-goals (see `ROADMAP.md`): no built-in Kubernetes, no extensions marketplace,
calf/
├── backend/ Go daemon
│ ├── cmd/calf/
│ │ └── main.go Entrypoint: config/logger/runtime/server wiring, signal handling, PID file, stale-port takeover
│ │ └── main.go Entrypoint: config/logger/runtime/server wiring, signal handling, PID file, stale-port takeover (cross-platform: lsof/Unix, netstat/Windows)
│ ├── internal/
│ │ ├── api/
│ │ │ ├── server.go Server struct, route registration for all /v1/... endpoints
Expand Down Expand Up @@ -142,7 +144,7 @@ calf/
│ └── .dockerignore
├── scripts/verify-docker-cli.sh Verifies `docker` CLI works against Calf's socket
├── .github/workflows/ci.yml CI: backend (vet/test/build) + ui (analyze/test/build) jobs, macos-latest
├── Makefile dev-backend / dev-ui / ui / clean / verify-docker-cli targets
├── Makefile dev-backend / dev-ui-macos / dev-ui-linux / dev-ui-windows / ui-macos / ui-linux / ui-windows / clean / verify-docker-cli / release / release-macos / release-linux / release-windows targets
├── README.md Project pitch + quick start
├── DEVELOPMENT.md Dev setup, config file example, Docker Desktop migration walkthrough
├── ROADMAP.md Phased plan, architecture diagram, non-goals, competitor comparison
Expand Down Expand Up @@ -207,7 +209,7 @@ Docker Hub OAuth2 device-code flow client. Polls for a token, decodes JWT claims
## UI File Reference (`ui/lib/`)

### `main.dart`
Builds a Material `ThemeData` bridged from a `ShadThemeData` (shadcn_ui), with a hardcoded brand primary color (`#2496ED`). Light/dark `ShadThemeData` instances are built once as top-level finals.
App entrypoint. Calls `_startDaemon()` to spawn the Go daemon binary (found next to the Flutter executable — `.app` bundle on macOS, alongside the binary on Linux/Windows) and waits for `/v1/status` to respond before showing the UI. Kills the daemon on app close. Inserts common Homebrew paths into `PATH` on macOS (no-op on other platforms). Builds a Material `ThemeData` bridged from a `ShadThemeData` (shadcn_ui), with a hardcoded brand primary color (`#2496ED`). Light/dark `ShadThemeData` instances are built once as top-level finals.

### `app_shell.dart`
Sidebar navigation (Containers / Images / Volumes / Builds) plus the settings screen, and a top bar showing Docker Hub registry sign-in status. `SettingsScreen` handles CPU/memory/swap slider configuration (bounded by host capacity from `/v1/config`), Docker Desktop migration trigger + polling, and theme mode switching.
Expand Down Expand Up @@ -250,10 +252,18 @@ Simple JSON files under `~/.config/calf/ui/<name>.json` (via `path_provider`'s a

```
make dev-backend # cd backend && CGO_ENABLED=0 go run ./cmd/calf
make dev-ui # flutter run -d macos
make ui # flutter build macos (alias: make build)
make clean # flutter clean
make verify-docker-cli # runs scripts/verify-docker-cli.sh
make dev-ui-macos # flutter run -d macos
make dev-ui-linux # flutter run -d linux
make dev-ui-windows # flutter run -d windows
make ui-macos # flutter build macos
make ui-linux # flutter build linux
make ui-windows # flutter build windows
make release # build Go daemon + Flutter app for all platforms
make release-macos # build Go daemon + macOS .app
make release-linux # build Go daemon + Linux bundle
make release-windows # build Go daemon + Windows bundle
make clean # flutter clean
make verify-docker-cli # runs scripts/verify-docker-cli.sh
```

CI (`.github/workflows/ci.yml`, both jobs on `macos-latest`):
Expand Down
64 changes: 55 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,32 +1,78 @@
.PHONY: help ui build clean dev dev-backend dev-ui verify-docker-cli
.PHONY: help ui-macos clean dev dev-backend dev-ui-macos verify-docker-cli release-macos \
ui-linux ui-windows dev-ui-linux dev-ui-windows release-linux release-windows release

help:
@echo "Calf — common commands"
@echo ""
@echo " make dev-backend API daemon on :8765 (terminal 1)"
@echo " make dev-ui Flutter app on macOS (terminal 2)"
@echo " make dev-backend API daemon on :8765 (terminal 1)"

@echo " make dev-ui-macos Flutter app on macOS (terminal 2)"
@echo " make dev-ui-linux Flutter app on Linux (terminal 2)"
@echo " make dev-ui-windows Flutter app on Windows (terminal 2)"

@echo ""
@echo " make ui-macos build macOS app"
@echo " make ui-linux build Linux app"
@echo " make ui-windows build Windows app"

@echo ""
@echo " make ui build macOS app"
@echo " make build build macOS app"
@echo " make clean remove build artifacts"
@echo " make release-macos build Go daemon + macOS app"
@echo " make release-linux build Go daemon + Linux app"
@echo " make release-windows build Go daemon + Windows app"
@echo " make release build for all platforms (macOS + Linux + Windows)"
@echo " make clean remove build artifacts"
@echo " make verify-docker-cli smoke-test docker CLI against Calf"
@echo ""
@echo "Full guide: DEVELOPMENT.md"

ui:
ui-macos:
cd ui && flutter build macos

ui-linux:
cd ui && flutter build linux

ui-windows:
cd ui && flutter build windows

release: release-macos release-linux release-windows

release-macos:
cd backend && CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o calf-daemon-amd64 ./cmd/calf
cd backend && CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o calf-daemon-arm64 ./cmd/calf
lipo -create -output backend/calf-daemon backend/calf-daemon-amd64 backend/calf-daemon-arm64
rm backend/calf-daemon-amd64 backend/calf-daemon-arm64
cd ui && flutter build macos
cp backend/calf-daemon ui/build/macos/Build/Products/Release/Calf.app/Contents/MacOS/calf-daemon
rm backend/calf-daemon
codesign --force --sign - --identifier com.enegalan.calf.daemon ui/build/macos/Build/Products/Release/Calf.app/Contents/MacOS/calf-daemon
codesign --force --sign - --entitlements ui/macos/Runner/Release.entitlements ui/build/macos/Build/Products/Release/Calf.app
codesign --verify --deep --strict ui/build/macos/Build/Products/Release/Calf.app

build: ui
release-linux: ui-linux
cd backend && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o calf-daemon ./cmd/calf
cp backend/calf-daemon ui/build/linux/x64/release/bundle/calf-daemon
rm backend/calf-daemon
Comment thread
coderabbitai[bot] marked this conversation as resolved.

release-windows: ui-windows
cd backend && CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o calf-daemon.exe ./cmd/calf
cp backend/calf-daemon.exe ui/build/windows/x64/runner/Release/calf-daemon.exe
rm backend/calf-daemon.exe

clean:
cd ui && flutter clean

dev-backend:
cd backend && CGO_ENABLED=0 go run ./cmd/calf

dev-ui:
dev-ui-macos:
cd ui && flutter run -d macos

dev-ui-linux:
cd ui && flutter run -d linux

dev-ui-windows:
cd ui && flutter run -d windows

verify-docker-cli:
./scripts/verify-docker-cli.sh

Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ Be a **valid** Docker Desktop replacement for local development: same CLI (`dock
### 3.1 Installation and lifecycle

- [ ] macOS installer (.dmg / .pkg) with signing and notarization
- [ ] Daemon as a user service (launchd / systemd)
- [x] Daemon embedded in .app bundle, spawned by Flutter app on launch, killed on close
- [ ] In-app updates
- [ ] Windows installer (WSL2 + integration)
- [ ] Linux installer (.deb / .rpm / AppImage)
Expand Down
Binary file removed backend/api.test
Binary file not shown.
Binary file removed backend/buildstore.test
Binary file not shown.
Loading
Loading