Open
Conversation
Reconciles disk state with runtime state to find and clean up: - Orphaned files: sandbox files on disk with no matching container - Orphaned containers: containers with no matching metadata on disk Dry run by default; use --force to actually remove orphaned resources.
LoadSandboxMetadata already defaults WorkspaceMode to "direct", so the fallback to "dir" was dead code.
Add a new internal/multiplexer package that provides a common Multiplexer interface for terminal multiplexer backends. Includes tmux and wezterm implementations with methods for init scripts, attach commands, session checking, window listing, host config mounts, and prompt instructions.
Add a Multiplexer string field to both Template and SandboxMetadata structs so the multiplexer type (tmux or wezterm) can be configured per-template and persisted per-sandbox. Add MuxSessionName alias for new code.
Replace hardcoded tmux logic in the generator with the multiplexer interface. TemplateData now uses MuxPackages/MuxInitScript instead of TmuxWindows. Container config uses multiplexer.New() to compute packages, init scripts, and host config mounts. Rename NoTmuxConfig to NoMuxConfig.
Replace tmux-specific health checks with multiplexer-aware versions. Rename StatusNoTmux to StatusNoMux, TmuxActive to MuxActive, TmuxWindows to MuxWindows. Check() and GetSummary() now accept a Multiplexer parameter. Update all callers: cmd/status, cmd/ps, tui/picker, tui/group.
Use multiplexer.PromptInstructions() instead of hardcoded tmux text in system prompts. Replace TmuxSession field with MuxInstructions in the system prompt template data, populated from the sandbox multiplexer type.
Rename NoTmuxConfig to NoMuxConfig in CreateOptions and ContainerConfig. Store the template Multiplexer field in sandbox metadata. Update the TUI wizard, cmd/up (add --no-mux-config, deprecate --no-tmux-config), and cmd/pick to use the new field names.
Use multiplexer.AttachCommand() in cmd/ssh and gateway to determine the SSH remote command. For wezterm, cmd/ssh detects TERM_PROGRAM and uses native wezterm connect; gateway falls back to interactive shell. Update cmd/gateway.go and internal/gateway/server.go similarly.
Replace the GitHub-based nix registry (type=github with rev) with a local store path registry (type=path with pkgs.path). Since /nix/store is bind-mounted from the host, this eliminates network fetches and nixpkgs evaluation on first use inside the sandbox. The registry is now unconditional — no Go-side NixpkgsRev needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove non-existent --workspace and --git-worktree flags from up command - Document all missing flags: --direct, --ssh-key, --ssh-key-path, --git-user, --git-email, --no-mux-config - Add gc command documentation (was completely undocumented) - Fix MODE values: dir → direct, git → git-worktree - Update getting-started example to use correct --repo --direct syntax - Rewrite jj-workspaces comparison table to reflect auto-detection behavior Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move the control mode detection logic into tmux.AttachCommand() so all callers automatically benefit. This fixes the inconsistency where `forage-ctl ssh` used tmux -CC in WezTerm but `forage-ctl pick` did not. Changes: - Tmux.AttachCommand() now checks terminal.SupportsControlMode() internally - Remove AttachCommandCC() as it's no longer needed - Add functional option WithControlMode(bool) for --no-tmux-cc override - ssh.go no longer needs to know about Tmux implementation details Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The identity system was only reading git config and setting git identity in the container. Since forage workspaces typically use jj, this caused commits to have empty author/committer fields. Changes: - ReadHostUserGitIdentity now checks jj config first (~/.config/jj/config.toml) - Add parseJJConfigIdentity for TOML config parsing - forage-agent-identity service now sets both git and jj identity Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add the injection package that defines the core abstraction for sandbox injection contributions. This replaces scattered hard-coded mappings with a unified contribution system. New types: - Mount: filesystem mount specification - EnvVar: environment variable - Package: installable package with optional version - PromptFragment: system prompt contribution - GeneratedFile: dynamically generated file content - Request types for contextual information New interfaces: - MountContributor: contribute filesystem mounts - PackageContributor: contribute packages to install - EnvVarContributor: contribute environment variables - InitCommandContributor: contribute init-time commands - PromptContributor: contribute to system prompts - GeneratedFileContributor: contribute generated files - TmpfilesContributor: contribute tmpfiles rules
…alization.framework VM - Mount host /nix/store (read-only) and nix-daemon socket into Apple containers - Detect platform mount config (Determinate Nix vs standard) for correct paths - Validate Nix store accessibility at container startup - Embed GeneratedFileMounter in AppleRuntime for file injection support - Add ContainerInfo() method for container environment info - Implement ViewLogs via 'container logs' CLI - Enable GeneratedFiles capability (was false) - Add configurable OCI image field (default: nixos/nix:latest) - Add Apple capabilities test ff-qos.1 ff-qos.2 ff-qos.6 ff-qos.11
JJBackend and GitBackend now implement PackageContributor so jj and git are installed inside OCI containers. Previously these were only available via NixOS environment.systemPackages on the nspawn path.
Embed the Dockerfile via go:embed so the fallback builds the full forage-base image locally instead of using bare nixos/nix:latest. The image includes agent user, HOME, nix-command/flakes, and base packages.
Apple Container doesn't support file bind mounts. Instead of silently skipping them, collect deferred file mounts and copy them into the container post-start via exec. Also wire up the local image build fallback for the Apple runtime.
Add .gitattributes to mark flake.lock as binary for merges, preventing broken three-way merges of the machine-generated JSON.
Remove environment.etc mode attribute (nix-darwin doesn't support it), fix forage-ctl Nix build to include Go module replacements via fileset, and make empty-templates message platform-agnostic.
Add token store (forage-ctl claude token {store,status,remove}) for
long-lived tokens from 'claude setup-token', with automatic keychain
passthrough as fallback for short sessions on macOS.
Containers cannot access the host keychain, so forage-ctl bridges the
gap by injecting CLAUDE_CODE_OAUTH_TOKEN at sandbox creation time.
Document the full authentication workflow in the mdbook docs.
Fix errcheck, gofmt, gosec, govet shadow, and staticcheck QF1012 issues flagged by CI.
Define goSrc and goModRoot once in flake.nix and pass them to both packages/forage-ctl/default.nix and tests/e2e/vm.nix, fixing the e2e build (which had the same ../../images/forage-base resolution issue) and eliminating duplication.
The e2e job had needs: [test], but test is skipped in the merge queue, which caused e2e to be skipped too.
Darwin support
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.
No description provided.