macOS VM engine, persistent PTY sessions, Go-native nix-cache pipeline - #44
Merged
Conversation
…ted into Go — CI hydration blocks drop from ~90 lines of shell to 6 lines each, and Taskfile's 48-line publish script becomes a single `cell nix-store push --volume` call - feat(nixstore): `nix-store push` splits uncompressed tar into ~512 MB OCI layers with per-chunk split-phase progress and upload throughput reporting — CI operators see `chunk N split (X MB in Ys at Z MB/s — P% of Total)` instead of silent stalls - feat(nixstore): `nix-store push --volume` reads directly from a Docker volume, handling tar creation, size estimation, retry with linear backoff, tag aliasing, and minimum-size skip internally — replaces 48 lines of Taskfile shell - feat(nixstore): `nix-store pull` extracts all non-base layers (not just the last one), supporting both legacy single-layer and new chunked multi-layer cache images - feat(nixstore): `nix-store pull --fallback` probes registry for the first available manifest from a candidate list — consolidates the 30-line shell `for c in $EXACT $LATEST; do docker manifest inspect` loop into Go - chore(ci): CI jobs run on GitHub-hosted ARM runners (`ubuntu-24.04-arm`) instead of Blacksmith — eliminates unexplained SIGTERM kills during nix-cache uploads; Buildx action replaces Blacksmith builder setup - chore(taskfile): nix-cache publish task calls `cell nix-store push --volume` with `--retries 3 --min-size 1GB`; `nix:update-hash` reimplemented without `nix-update` dependency; `debug:macos` and `debug:nix` diagnostic tasks added
…nger crash on QEMU seccomp, and dangling /etc symlinks in the shared nix-store volume no longer break nix.conf
- fix(runner): disable sandbox, filter-syscalls, and extra-platforms in nix.conf when the target arch differs from the host — under QEMU userspace emulation, seccomp BPF programs contain guest-arch syscall numbers that the host kernel rejects with "unable to load seccomp BPF program: Invalid argument"
- fix(runner): materialise dangling /etc/{passwd,group,shadow,nix/nix.conf} symlinks from the base-system store path before anything touches /etc — newer nixos/nix images symlink these into /nix/store, which dangles when the shared nix-store volume is mounted over /nix
- feat(runner): `DEVCELL_ARCH` env override steers `DetectArch()` and `DockerPlatform()`, and cross-arch builds automatically use a separate nix-store volume (`devcell-nix-store-amd64`) to avoid mixing architectures
- feat(runner): `PreflightPlatformCheck` runs `nix eval` on the flake's `platformStrictCheck` attribute before building — catches incompatible packages early with an actionable error instead of a deep nix build failure
- feat(runner): GC roots are scoped per project (`/nix/var/nix/gcroots/devcell/<project>-<target><arch>`) so different projects don't overwrite each other's store references
- chore(runner): pin nix base image to `nixos/nix:2.34.7`, add `--device=/dev/fuse` and `DockerCapAdd` support to `BuildArgv`, decouple `FlakeNixImage()` from binary version
…ia a persistent PTY session — conversation context persists across API requests and per-request cold-start overhead is eliminated - feat(ptyctl): add `internal/ptyctl` package — wraps charmbracelet xpty + vt terminal emulator to manage a persistent virtual terminal, with `Send()` to type prompts, `WaitReady()` to detect the input marker, and `ReadScreen()` to scrape the current terminal contents - feat(serve): add `PTYExecutor` in `internal/serve/pty_exec.go` — implements the `Executor` interface by typing prompts into a persistent Claude TUI session and scraping responses from the terminal buffer, with configurable ready-marker detection, response timeout, and output stabilisation delay - feat(serve): `--pty` flag on `cell serve` selects `PTYExecutor` over the default `ShellExecutor` — operators choose persistent-session mode at startup; the two executors share the same HTTP API surface - test(ptyctl): login flow test validates the terminal can detect Claude's authentication prompt and extract the login URL from terminal output - test(serve): PTYExecutor unit tests cover ready detection, prompt/response round-trip, and timeout behaviour; integration test validates end-to-end HTTP request through the PTY path
…` provisions and launches interactive macOS VMs on bare-metal Macs without Docker - feat(vm/tart): add `internal/vm/tart` package (35 files) — OCI image download via `tart pull`, VM lifecycle management (clone, start, stop, force-stop), guest agent readiness detection, VirtioFS directory sharing, DHCP lease parsing for IP resolution, SSH/exec command execution, VNC screenshot + OCR for boot automation, and disk image patching for nix-darwin provisioning - feat(cmd): `cell build --engine=tart` acquires an OCI base image, clones it as the cell's instance VM, provisions nix-darwin via boot commands + `tart exec`, creates a provisioning marker, and supports `--force` to recreate and `--no-cache` to re-download; darwin-only with build-tag stubs for non-darwin - feat(cmd): `cell init --engine=tart` generates a `.devcell.toml` pre-configured for tart with OCI image, SSH settings, and engine field - feat(cmd): `cell shell --engine=tart` (via `runTartAgent`) creates a session user matching host `$USER` via `dscl`, sets up home directory, mounts the project via VirtioFS, and opens an interactive PTY shell with `tart exec -t -i`; supports `--background` to keep the VM running after exit - feat(cfg): add tart-specific TOML fields (`tart_ssh_port`, `tart_ssh_host`, `tart_ssh_user`, `tart_ssh_key`, `tart_oci_image`), `background` flag, `docker_cap_add` list, and `[nix]` section with `nixhome` and `image` fields; `LoadFromOS` replaced by `LoadFromOSWithDirs` returning explicit errors - feat(cmd): `--engine` flag accepts `tart` alongside `docker`/`vagrant`; `--background` flag added as persistent root flag; `applyOutputFlagsWithLog` opens a debug log file to `.devcell/debug/` when `--debug` is active
…version` reports BuildDate from all build paths, and subcommands get per-command debug log files
- feat(ux): `InitDebugLog` opens a timestamped log file at `.devcell/debug/<ts>-<cmd>.log` when `--debug` is active — `Debugf` writes to both stdout and the file so debug output survives terminal scrollback loss; `CloseDebugLog` flushes on exit
- feat(ux): `applyOutputFlagsWithLog` wires per-subcommand debug logging into `chrome`, `rdp`, `vnc`, and `models` commands
- feat(build): goreleaser stamps `BuildDate` into the binary via `-X version.BuildDate={{.Date}}` — `cell --version` now includes the build timestamp on release binaries
- feat(build): nix flake stamps `Version`, `GitCommit`, and `BuildDate` via ldflags — `nix build .#cell` produces a binary with the same version info as Taskfile and goreleaser builds
- test(ux): `TestDebugfWritesToLogFile` verifies dual-output behaviour; `TestInitDebugLog_NoopWhenNotVerbose` confirms no file is created without `--debug`
- test(cmd): `TestInitFlowEngine` validates `--engine=tart` init flow dispatches correctly with tart-specific TOML fields
…update packages across financial/travel/security/graphics/infra/electronics/qa-tools modules - feat(nixhome): add `social.nix` module — Mastodon MCP server (post, reply, follow, search, trending, timelines) built from source as a Python application - feat(nixhome): add `wine.nix` module — Wine staging + winetricks + dependencies for running Wails3 Windows apps under Wine with WebView2 runtime - feat(nixhome): add darwin VM home-manager targets (`devcell-*-darwin`) in `flake.nix` — `cell init --engine=tart` provisions macOS VMs via `home-manager switch --flake .#devcell-ultimate-darwin` - chore(nixhome): ultimate stack adds `social` and `wine` modules, removes `android` module; financial module adds `firefly-iii` MCP server - chore(nixhome): update packages across modules — codex wrapper gains conversation history/resume support, travel adds nominatim geocoding MCP, security adds reconftw/amass/httpx, electronics switches to kicad-mcp v2, graphics updates inkscape-mcp, infra adds notion-api MCP, qa-tools adds playwright MCP config - chore(nixhome): `base.nix` trims redundant packages, `mise.nix` adds trust/settings helpers, `macos/` hosts gain darwin-specific paths and Homebrew integration - test(nixhome): add `managed_mcp_staging_test.go` for MCP server staging validation; update `modules_2_0_integration_test.go` with new module list
… sed -i incompatibility on macOS
Contributor
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
devcell | 786eae7 | Commit Preview URL Branch Preview URL |
Jul 20 2026, 08:17 PM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--engine=tart) —cell build/init/shellcan now provision and launch interactive macOS VMs on bare-metal Macs, with VNC-based boot automation, disk patching, nix volume passthrough, and home-manager provisioningcell serve --pty— persistent PTY session keeps Claude's conversation context alive across API requests, eliminating cold-start overhead fromclaude -psubprocess spawningcell nix-store push/pullreplaces crane CLI — true streaming push (no temp files), 512 MB chunked uploads with sent/total progress, and CI drops an external tool dependency; Taskfile's 48-line publish script becomes a singlecell nix-store push --volumecallDEVCELL_ARCH=amd64on ARM no longer crashes on QEMU seccomp; dangling /etc symlinks in shared nix-store volumes no longer break nix.conf--debugwrites a persistent log file alongside stdout;cell --versionreports BuildDate from all build pathsnix:update-vendor-hashpre-commit hook (macOS BSD sed compatibility)New files (notable)
internal/vm/tart/— full macOS VM lifecycle: acquire, boot, provision, SSH, VNC client, disk patching, nix volume management (~30 files, ~8K LOC with tests)internal/serve/pty_exec.go— PTYExecutor implementation with screen-diff response extractioninternal/ptyctl/ptyctl.go— PTY control layer (charmbracelet/x/xpty + vt terminal emulator)internal/nixstore/volume.go— Docker volume tar-pipe push/pull for nix-store cachecmd/tart_runner.go— tart engine agent runner (parallel to Docker'srunAgent)cmd/build_tart_darwin.go—cell build --engine=tartwith VNC boot automation + home-manager provisioningnixhome/modules/social.nix— Mastodon MCP server built from sourcenixhome/modules/wine.nix— Wine staging + winetricks for Wails3 Windows app testingNeed help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.