ghfs

v1.1.0

2026-09-18

v1.1.0 corrects the macOS requirements and fixes the paths where ghfs could hand a reader incomplete or wrong issue content.

Breaking Changes

macOS 26 and macFUSE 5.4.0 or later are now required

ghfs mounts through the macFUSE File System Extension, and macFUSE offers that extension only on macOS 26 or later. Earlier releases of ghfs documented “macOS 15.4 or later”, which was never correct. macOS 15 is no longer supported.

macFUSE 5.4.0 or later is also required. Earlier macFUSE releases duplicate directory entries and can lose the volume while ghfs is reading a file.

On macOS, install macFUSE first, enable the macFUSE File System Extension in System Settings > General > Login Items & Extensions > File System Extensions, and then install ghfs.

Linux and WSL 2 requirements are unchanged.

Bug Fixes

Directory listings were truncated, duplicated, or empty

On macOS, a directory with many entries stopped at 63 entries and the rest were invisible. Listing the same directory twice within 500 ms returned nothing the second time, and tree could see entries twice or see none at all. An agent that listed .ghfs/ twice in a row could read it as holding no issues, with no error anywhere.

ghfs now resumes a listing from the offset it was given and no longer keeps a short-lived cache of directory entries. A directory returns all of its entries however many it holds, and repeated listings return the same result.

Reading an issue file could return content that was never in the file

With macFUSE 5.4.0, a zero-length read reply makes read(2) report that it read the requested length while writing nothing into the caller’s buffer. The caller then uses whatever its buffer already held, and the failure is invisible. Background sync can shrink an issue while a reader is still working from the size reported earlier, which is how ghfs reached that reply. On macFUSE 5.3.x and earlier, the same reply crashed the File System Extension and took the volume with it.

ghfs now fixes an issue file’s content when the file is opened, so the reply is never zero-length.

Background sync skipped repositories whose issues were active

Polling decided whether a repository was active from the repository’s own update time, which does not change when an issue is updated. A repository whose issues were moving but whose repository record was old could be skipped entirely. Activity is now judged from the newest issue update, and a skip is recorded in the log.

A disabled File System Extension caused a restart loop

When the macFUSE File System Extension was not enabled, the daemon crashed while mounting, the service manager restarted it, and the log grew without limit. The daemon now records consecutive mount failures and stops retrying, and ghfs doctor reports the reason and how to enable the extension.

There is no way to read the extension’s state before mounting, so the mount failure itself is what ghfs reports.

The daemon reported a successful mount that had failed

When volume registration failed, the daemon still logged FUSE mounted and kept running. The mount point stayed an empty directory and nothing indicated an error. The daemon now reads the mount table before and after mounting and treats the mount as successful only when a new entry has appeared.

Checking for a leftover mount could hang

After the daemon ended abnormally, ghfs checked the mount point by reading the directory. While a leftover macFUSE file system module holds that path, any read of it never returns and cannot be interrupted, so the check itself hung. The daemon, ghfs doctor, and the release tests now read the mount table instead. The daemon stops before attempting to mount and prints the recovery steps.

Improvements

Daemon logs rotate

Running as a service, the daemon writes to ~/.ghfs/logs/daemon.log by default, switches files at 10 MB, and keeps 3 generations. log_file, log_max_size, and log_max_backups configure this. Started from a terminal, ghfs daemon start still writes to stderr only.

ghfs doctor reports more

On macOS, ghfs doctor now reports whether macFUSE is installed and which version it is, and lists recorded consecutive mount failures with their reasons.

install.sh checks the macOS and macFUSE versions

The installer now warns when the machine runs macOS earlier than 26, when macFUSE is older than 5.4.0, and when macFUSE is absent. It warns; it does not stop the installation.

Known Limitations

Recovering from an abnormal daemon exit takes a manual step (macOS)

When the daemon ends abnormally, the macFUSE file system module keeps holding the volume. ghfs cannot tell which module holds which volume, so it cannot clear this on its own.

  • ghfs does not start again until the module is quit by hand
  • quit it with pkill -f io.macfuse.app.fsmodule.macfuse
  • this quits the module for every macFUSE volume on the machine, so unmount other macFUSE volumes first
  • no reboot is needed

ghfs doctor and the daemon’s startup error both print these steps.

A listing split across calls can miss or repeat entries

A large directory is returned over several calls. If background sync changes the directory between calls, an entry can be missed, skipped, or returned twice. Issue counts change only at the polling interval, so a change has to land inside a short window for this to happen, and no occurrence has been observed. How the resume position should be anchored is not settled.

An issue that changes state can stay in open/ for up to 5 minutes (Linux)

On Linux the mount is set up with entry_timeout=300, matching the default five-minute polling interval. After an issue is closed, its file can remain visible under open/ until that cache expires.

Supported Platforms

  • macOS 26 or later, Apple Silicon, with macFUSE 5.4.0 or later
  • Linux x86_64 / ARM64 with libfuse3
  • Windows through WSL 2, using the Linux build

Installation

curl -fsSL https://ghfs.dev/install.sh | sh

An existing installation updates with ghfs update.