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
12 changes: 9 additions & 3 deletions .cursor/rules/calf.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ calf/
│ │ │ ├── images.go Image list/inspect/remove endpoints
│ │ │ ├── logs.go Log streaming endpoints (WebSocket)
│ │ │ ├── volumes.go Volume CRUD + subresources
│ │ │ ├── networks.go Network list/inspect/remove endpoints
│ │ │ ├── migrate.go Docker Desktop migration orchestration + status polling
│ │ │ ├── registry.go Registry login/logout
│ │ │ └── registry_login.go Docker Hub OAuth device-flow browser login
Expand All @@ -80,6 +81,8 @@ calf/
│ │ │ ├── lima.go Lima runtime: manages the Lima VM, runs ops via `limactl shell ... nerdctl`
│ │ │ ├── lima.yaml Embedded Lima VM template (go:embed)
│ │ │ ├── nerdctl.go Shared nerdctl output parsing, compose project inference, log filtering
│ │ │ ├── network.go Network list/inspect/remove via nerdctl
│ │ │ ├── proxy.go HTTP/HTTPS proxy application in VM/native runtime
│ │ │ ├── mock.go In-memory Runtime implementation used by backend tests
│ │ │ ├── exec.go exec.CommandContext wrapper with transient-error retry
│ │ │ ├── exec_attach.go PTY-based interactive exec attach (stdin/stdout/resize)
Expand Down Expand Up @@ -122,6 +125,7 @@ calf/
│ │ │ ├── container_detail_screen.dart Tabs: logs/inspect/mounts/exec/files/stats (fl_chart, xterm)
│ │ │ ├── compose_group_detail_screen.dart Mixed-color log view per compose project
│ │ │ ├── resources_screen.dart Images/Volumes/Builds screens
│ │ │ ├── networks_screen.dart Network list and detail screens
│ │ │ ├── volume_detail_screen.dart Stored-data / containers-in-use / exports tabs
│ │ │ ├── volume_quick_export_screen.dart Quick export destination picker
│ │ │ └── volume_schedule_export_screen.dart Schedule export configuration
Expand Down Expand Up @@ -154,7 +158,7 @@ calf/
Entrypoint. Loads config, builds the logger, constructs the `runtime.Runtime` and `api.Server`, handles `SIGINT`/`SIGTERM` via `signal.NotifyContext`, manages a PID file at `~/.config/calf/calf.pid`, and has `ensurePort` logic that terminates a stale previous `calf` process holding the listen port before starting. The runtime starts asynchronously in a goroutine (failure is non-fatal at startup); shutdown stops both the HTTP server and the runtime with timeouts.

### `internal/config/`
- `config.go` — defines the `Config` struct (`listen_addr`, `log_level`, `vm_name`, `docker_socket`, `poll_interval_ms`, `cpus`, `memory_gb`, `memory_swap_gb`, `disk_gb`). Loads/saves as YAML at `~/.config/calf/config.yaml`, with defaults embedded via `//go:embed config.yaml`, a `withDefaults` backfill step, and `migrateLegacyDefaults` (rewrites the old `:8080` port to `:8765`).
- `config.go` — defines the `Config` struct (`listen_addr`, `log_level`, `vm_name`, `docker_socket`, `poll_interval_ms`, `cpus`, `memory_gb`, `memory_swap_gb`, `disk_gb`, `http_proxy`, `https_proxy`, `no_proxy`). Loads/saves as YAML at `~/.config/calf/config.yaml`, with defaults embedded via `//go:embed config.yaml`, a `withDefaults` backfill step, and `migrateLegacyDefaults` (rewrites the old `:8080` port to `:8765`).
- `logger.go` — wraps `slog.NewTextHandler` with a level parser (`debug`/`warn`/`error`, default `info`).

### `internal/api/`
Expand All @@ -169,7 +173,7 @@ HTTP server built on `net/http.ServeMux`. Every handler follows the same shape:
- `runtime_ready.go` — blocks until the runtime is running (3-minute timeout); used before registry login.
- `runtime_errors.go` — maps `ErrRuntimeNotRunning` to `503`.
- `builds.go` — in-memory build history; `POST` triggers `RunBuild`.
- `containers.go` / `exec.go` / `images.go` / `logs.go` / `volumes.go` — CRUD plus subresources (logs, inspect, mounts, files, exec, stats). Exec/logs use WebSocket; other operations use one-shot HTTP.
- `containers.go` / `exec.go` / `images.go` / `logs.go` / `volumes.go` / `networks.go` — CRUD plus subresources (logs, inspect, mounts, files, exec, stats). Exec/logs use WebSocket; other operations use one-shot HTTP.
- `migrate.go` — orchestrates the Docker Desktop migration in a background goroutine, exposes status polling.
- `registry.go` / `registry_login.go` — basic registry login/logout plus Docker Hub OAuth device-flow browser login with session polling.

Expand All @@ -189,7 +193,7 @@ Docker Hub OAuth2 device-code flow client. Polls for a token, decodes JWT claims
### `internal/runtime/` (core abstraction)
- `runtime.go` — defines the `Runtime` interface (~30 methods: lifecycle, containers, images, volumes, builds, logs, exec, stats, registry) and shared JSON-tagged (snake_case) types (`Status`, `Container`, `Image`, `Volume`, `Build`, ...). `runtime.New(...)` selects `NewNative` on Linux, otherwise `NewLima`.
- `native.go` — `Native` runtime: talks directly to a `nerdctl`/`docker.sock` already available on the Linux host, no VM involved.
- `lima.go` — `Lima` runtime: manages a Lima VM (embeds a `lima.yaml` template via `go:embed`), starts/creates/stops the instance via `limactl`, runs all container operations via `limactl shell <vm> -- sudo nerdctl ...`. Includes `localhostProxies` for macOS port-forwarding and conflict detection.
- `lima.go` — `Lima` runtime: manages a Lima VM (embeds a `lima.yaml` template via `go:embed`), starts/creates/stops the instance via `limactl`, runs all container operations via `limactl shell <vm> -- sudo nerdctl ...`. Includes `localhostProxies` for macOS port-forwarding and conflict detection, `host.docker.internal` via Lima `hostResolver`, sleep/wake proxy resync, and proxy application.
- `nerdctl.go` — shared low-level helpers: JSON-line parsing of `nerdctl ps/images/volume ls/history` output, compose project/service inference, log-line noise filtering, log streaming plumbing.
- `mock.go` — in-memory `Mock` implementation of the full `Runtime` interface, used by backend tests.
- `exec.go` — generic `exec.CommandContext` wrapper with retry logic (`runCommandWithRetry`, retries only on `isTransientCommandError`).
Expand Down Expand Up @@ -227,6 +231,7 @@ Simple JSON files under `~/.config/calf/ui/<name>.json` (via `path_provider`'s a
- `container_detail_screen.dart` — tabs for logs/inspect/mounts/exec/files/stats, using `fl_chart` and `xterm`.
- `compose_group_detail_screen.dart` — mixed-color log view per compose project.
- `resources_screen.dart` — Images/Volumes/Builds screens.
- `networks_screen.dart` — Network list (name + subnet) and detail (driver, scope, gateway, options).
- `volume_detail_screen.dart` — stored-data / containers-in-use / exports tabs.
- `volume_quick_export_screen.dart` — quick export destination picker (local file, image, registry).
- `volume_schedule_export_screen.dart` — schedule export configuration (daily/weekly/monthly).
Expand Down Expand Up @@ -274,6 +279,7 @@ CI (`.github/workflows/ci.yml`, both jobs on `macos-latest`):
9. **Commit messages:** conventional-commit style (`feat:`, `fix:`, `refactor:`, `chore:`), optionally scoped (`feat(runtime): ...`, `fix(ui): ...`).
10. **Concurrency and resource lifecycle (Go).** Thread `context.Context` with explicit timeout/cancellation from every HTTP handler into the runtime layer — never use bare `context.Background()` for a blocking call inside a handler. Every long-lived goroutine (log broadcasting, migration, polling) must observe cancellation/a stop signal and be stopped on server shutdown — no fire-and-forget goroutines. Release resources with `defer` right next to acquisition (`defer f.Close()`, `defer mu.Unlock()`, `defer cancel()`).
11. **Versioning and living docs.** Bump `backend/version/version.go` and `ui/pubspec.yaml` together for every release. Add a `CHANGELOG.md` entry for every user-visible change. Whenever a file is added/removed/renamed under `backend/` or `ui/lib/`, update the Project layout tree and file reference sections in both `CLAUDE.md` and `.cursor/rules/calf.mdc` in the same change — keep both files equivalent and in sync with the codebase.
12. **CHANGELOG in user language.** CHANGELOG entries must describe changes from the user's perspective — no implementation details, library names, file paths, or protocol jargon. Write what users see and feel, not how it was built.

## Before making changes

Expand Down
75 changes: 36 additions & 39 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,61 @@ 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.4.0] - 2026-07-05
## [0.6.0] - 2026-07-06

### Changed

- **Proxy settings** redesigned with clearer layout, icons for each field, and one-tap clear buttons

## [0.5.0] - 2026-07-05

### Added

- Volume **Exports** tab with export history and download
- **Quick export** to a local tar file, an existing local image, a new image built from the volume, or a registry push
- Export file/image name patterns with `{volume}` and `{timestamp}` placeholders (static names allowed with overwrite warning)
- **Scheduled exports** with per-weekday times, enable/disable from the schedule list, and a background scheduler in the daemon
- Backend volume export API: `GET/POST /v1/volumes/{name}/exports` and `GET .../exports/{id}/download`
- Backend schedule API: `GET/POST /v1/volumes/{name}/export-schedules` and `PUT/DELETE .../export-schedules/{id}`
- **Networks screen** in the sidebar — browse networks and see their details
- **Proxy settings** in Settings — configure HTTP, HTTPS, and no-proxy for image downloads
- **host.docker.internal** now works from inside containers on macOS
- Port forwarding from containers now recovers automatically after sleep/wake

## [0.3.0] - 2026-07-01
## [0.4.0] - 2026-07-05

### Added

- Lima VM runtime on macOS with containerd, nerdctl, and Docker socket forwarding
- Linux native runtime path via nerdctl
- `calf start`, `calf stop`, and `calf status` CLI commands
- Container and image REST API endpoints
- WebSocket container log streaming at `/v1/containers/{id}/logs`
- Flutter UI screens for containers, images, and live logs
- `examples/hello-world/` reference project
- `scripts/verify-docker-cli.sh` P0 Docker CLI verification script
- Docker Desktop migration guide in `DEVELOPMENT.md`
- **Volume exports** — download a snapshot of any volume as a tar file
- **Quick export** — send a volume to a local file, an existing image, a new image, or a registry
- **Scheduled exports** — set up daily, weekly, or monthly exports with per-weekday schedules

### Changed
## [0.3.0] - 2026-07-01

### Added

- `/v1/status` now includes runtime mode, state, and Docker socket path
- Go tests moved to `backend/test/`
- First usable release with container and image management
- **macOS support** via a managed Linux VM
- **Linux support** running directly on the host
- Start, stop, and check status from the command line
- **Containers screen** — list, start, stop, delete containers
- **Images screen** — browse and delete images
- **Live logs** — stream container logs in real time
- Reference project in `examples/hello-world/`

## [0.2.0] - 2026-07-01

### Added

- Daemon layout under `backend/cmd/calf` with `internal/api` and `internal/config`
- Versioned REST API: `GET /v1/health`, `GET /v1/status`
- Persistent configuration at `~/.config/calf/config.yaml`
- Structured logging (`slog`), request logging, and panic recovery middleware
- Flutter UI with sidebar navigation, daemon status, and read-only settings screens
- `Makefile` for local builds (`make backend`, `make ui`, `make build`)
- GitHub Actions CI on macOS for backend and Flutter UI
- Basic sidebar navigation between screens
- **Settings screen** — read-only view of configuration
- Status banner showing daemon connection state
- Configuration file saved at `~/.config/calf/config.yaml`
- Build scripts for development

### Changed

- Backend entry point moved from `go run .` to `go run ./cmd/calf`
- UI now consumes `/v1/status` instead of `/hello`

### Removed

- `/hello` placeholder endpoint
- Backend restructured for easier development

## [0.1.0] - 2026-07-01

### Added

- Project scaffolding
- Go backend (`backend/`) with HTTP API
- CORS support on API routes for local UI development
- Flutter UI (`ui/`) with `shadcn_ui`, fetching daemon response on startup
- `DEVELOPMENT.md` with quick-start instructions for backend and UI
- `README.md` with project overview and MIT license reference
- Project bootstrap with Go backend and Flutter UI
- Health check endpoint
- CORS support for local development
- Quick-start guide in `DEVELOPMENT.md`
Loading
Loading