Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

FUSE Composition Layer

The FUSE composition layer provides a unified filesystem view of your repository and its dependencies at a fixed mount location. This enables:

  • Predictable paths for remote cache compatibility
  • Transparent editing of external dependencies
  • Automatic consistency management during updates

Quick Start

Manual (ad-hoc)

# Start the daemon for a single repo
turnkey-composed start --mount-point ~/firefly/turnkey --repo-root . --backend fuse

# Work from the mount point
cd ~/firefly/turnkey
buck2 build root//...

# Stop
turnkey-composed stop
# Install the service (runs on login)
turnkey-composed install --start

# Edit the config to declare your mounts
vim ~/.config/turnkey/composed.toml

With home-manager (declarative)

{
  imports = [ turnkey.homeManagerModules.turnkey-composed ];

  services.turnkey-composed = {
    enable = true;
    package = turnkey.packages.${system}.turnkey-composed;
    mounts = {
      myproject = {
        repo = "/Users/me/src/myproject";
        mountPoint = "/firefly/myproject";
      };
    };
  };
}

Prerequisites

Linux

# Verify FUSE is available
ls /dev/fuse

# If missing, install fuse3
sudo apt install fuse3  # Debian/Ubuntu
sudo dnf install fuse3  # Fedora

macOS

Install FUSE-T (no kernel extension, works on Apple Silicon):

brew install macos-fuse-t/homebrew-cask/fuse-t

Mount points under /: macOS root is read-only. The daemon automatically manages /etc/synthetic.conf entries and activates them via apfs.util -t when a mount point like /firefly/turnkey is requested. This requires sudo (the daemon prompts when needed).

For paths under ~ (e.g., ~/firefly/turnkey), no special setup is needed.

Service Configuration

The service reads ~/.config/turnkey/composed.toml:

# Mount a project
[[mounts]]
repo = "/Users/me/src/myproject"
mount_point = "/firefly/myproject"

# Mount another project
[[mounts]]
repo = "/Users/me/src/other-project"
mount_point = "/firefly/other"
backend = "fuse"  # Optional: "auto" (default), "fuse", or "symlink"

The daemon watches this file for changes. When you add a new [[mounts]] entry, the daemon picks it up and mounts it automatically — no restart needed.

Home-Manager Module

The declarative alternative to editing the TOML file directly:

{
  imports = [ turnkey.homeManagerModules.turnkey-composed ];

  services.turnkey-composed = {
    enable = true;
    package = turnkey.packages.${system}.turnkey-composed;
    mounts = {
      myproject = {
        repo = "/Users/me/src/myproject";
        mountPoint = "/firefly/myproject";
      };
      other = {
        repo = "/Users/me/src/other";
        mountPoint = "/firefly/other";
        backend = "fuse";  # Optional
      };
    };
  };
}

This generates the config file and manages the launchd agent (macOS) or systemd user service (Linux).

Service Management

# Install and start the service
turnkey-composed install --start

# Uninstall the service
turnkey-composed uninstall

# The service runs `turnkey-composed serve` which:
# - Reads ~/.config/turnkey/composed.toml
# - Builds cells via nix for each repo
# - Mounts all entries
# - Watches for config and manifest changes

How Cell Discovery Works

On startup, turnkey-composed:

  1. Runs nix eval to list *-cell packages from each repo's flake
  2. Runs nix build to build all cells in a single invocation (~3-4s if cached)
  3. Uses the Nix store paths to populate external/ in the FUSE mount

Cells are always built from the current flake state. The daemon watches manifest files (go-deps.toml, rust-deps.toml, etc.) and rebuilds cells automatically when they change.

Mount Structure

/firefly/myproject/
├── .buckconfig             # Virtual - generated by layout
├── .buckroot               # Virtual - marks Buck2 root
├── root/                   # Pass-through to your repository
│   ├── src/
│   ├── docs/
│   ├── flake.nix
│   └── ...
└── external/               # Dependency cells (from Nix store)
    ├── godeps/
    ├── rustdeps/
    ├── prelude/
    ├── toolchains/
    └── ...

Buck2 runs from the mount root. Source targets use the root// cell prefix: buck2 build root//src/cmd/tk:tk.

CLI Reference

Single Mount

# Start (foreground)
turnkey-composed start --mount-point <path> --repo-root <path> [--backend fuse|symlink|auto]

# With explicit config file
turnkey-composed start --config <path>

Service Mode

# Run as a service (reads ~/.config/turnkey/composed.toml)
turnkey-composed serve [--config <path>]

# Install/uninstall the system service
turnkey-composed install [--start]
turnkey-composed uninstall

Control

turnkey-composed status     # Check daemon status
turnkey-composed refresh    # Trigger manual cell rebuild
turnkey-composed stop       # Stop the daemon

Platform Notes

Linux

Uses native FUSE via /dev/fuse with the fuser Rust crate. Best performance.

macOS

Uses FUSE-T with direct C FFI bindings to libfuse3. FUSE-T translates FUSE operations to NFS internally. No kernel extension required.

The daemon handles synthetic firmlinks automatically for mount points under / (manages /etc/synthetic.conf and runs apfs.util -t).

Fastest for CI. No daemon needed. Automatically selected when FUSE is unavailable.

Integration with IDEs

VS Code / Cursor

{
  "go.goroot": "/firefly/myproject/root",
  "rust-analyzer.linkedProjects": ["/firefly/myproject/root/Cargo.toml"]
}

IntelliJ / GoLand

Set the project root to the FUSE mount point for consistent path resolution.