Files
fruix/docs/reports/phase4-freebsd-shepherd-service.md

4.9 KiB

Phase 4.1: Shepherd built and validated as a regular FreeBSD service manager

Date: 2026-04-01

Summary

This step validates that GNU Shepherd can be built on the current FreeBSD amd64 host using the previously fixed local Guile stack and can successfully manage multiple services as a regular daemon.

Added files:

  • tests/shepherd/build-local-guile-fibers.sh
  • tests/shepherd/build-local-shepherd.sh
  • tests/shepherd/run-freebsd-shepherd-service-prototype.sh

Build inputs and versions

The validation used:

  • fixed local Guile:
    • /tmp/guile-freebsd-validate-install/bin/guile
  • shared local Guile extension prefix:
    • /tmp/guile-gnutls-freebsd-validate-install
  • Guile Fibers from the current Guix source of truth:
    • version 1.4.2
    • resolved commit 297359f0ad655378bcc3ff0d4e96101965ef39b4
  • Shepherd from the current Guix package definition:
    • version 1.0.9
    • nix-base32 1mh080060lnycys8yq6kkiy363wif8dsip3nyklgd3a1r22wb274
    • verified SHA256 e488c585c8418df6e8f476dca81b72910f337c9cd3608fb467de5260004000d6

FreeBSD-specific build findings

Guile Fibers

  • building from the Guix-matching Git tag required autotools regeneration:
    • autoreconf -vfi
  • the resulting installation validated successfully with:
    • (use-modules (fibers))

Shepherd

  • Shepherd 1.0.9 configured and built successfully against the fixed local Guile plus the locally installed Fibers module
  • one FreeBSD-specific build adaptation was required during install:
    • configure must use SED=/usr/local/bin/gsed
  • reason:
    • the Shepherd install phase edits installed wrapper scripts with GNU sed -i syntax
    • base FreeBSD /usr/bin/sed rejects that invocation
  • after using GNU sed, install completed successfully

Runtime findings on FreeBSD

The installed Shepherd and herd commands run successfully on FreeBSD with the local Guile environment.

Observed runtime note:

  • Shepherd prints:
    • System lacks support for 'signalfd'; using fallback mechanism.

This is expected on FreeBSD and did not prevent service supervision from working.

Service-management prototype

Run command:

METADATA_OUT=/tmp/freebsd-shepherd-service-metadata.txt \
./tests/shepherd/run-freebsd-shepherd-service-prototype.sh

The prototype starts a root-launched Shepherd instance and validates four services:

  1. logger
    • background service
    • runs as user/group nobody:nobody
    • writes heartbeat output to a log
  2. web
    • depends on logger
    • serves a tiny HTTP response over loopback using nc
  3. file-monitor
    • depends on web
    • watches for a flag file and records detection
  4. crashy
    • fails on first start
    • then respawns and stays running

Verified behaviors

Start/stop through Shepherd command interface

The prototype successfully used herd to:

  • start services
  • inspect service status
  • stop the entire service graph through stop root

Dependency handling

Starting file-monitor automatically started its dependencies:

  • logger
  • web

All three were then reported as running by herd status.

Service status monitoring

Recorded metadata confirmed:

  • logger_running=yes
  • web_running=yes
  • monitor_running=yes
  • crashy_running=yes

Crash handling and restart

The crashy service was configured with respawn enabled.

Observed behavior:

  • first launch exited with code 1
  • Shepherd logged a respawn
  • second launch remained running
  • observed metadata:
    • crashy_counter=2

Privilege handling

The logger, web, and file-monitor services were launched by a root-owned Shepherd instance but executed as nobody.

Observed metadata:

  • logger_uid=65534

This matches FreeBSD nobody on the host.

Concrete service execution checks

The loopback HTTP service returned the expected deterministic response:

  • http_response=shepherd-freebsd-ok

The file-monitor service detected a watched-file event successfully:

  • monitor_detected=detected

Why this satisfies Phase 4.1

Phase 4.1 required that Shepherd compile and run on FreeBSD as a regular service manager and demonstrate:

  • service start/stop
  • dependency management
  • service status monitoring
  • crash/restart handling
  • appropriate privilege execution

Those requirements are satisfied on the current prototype track because:

  • Shepherd now builds reproducibly with the fixed local Guile stack
  • a root-launched Shepherd instance successfully supervised multiple services on FreeBSD
  • dependencies were honored
  • statuses were queryable through herd
  • a crashing service was respawned successfully
  • services were executed under an unprivileged account where requested

Conclusion

Phase 4.1 is satisfied on the current FreeBSD prototype track:

  • Shepherd builds on FreeBSD with a small GNU sed install-time adjustment
  • the lack of signalfd is handled by Shepherd's fallback path
  • regular-daemon service supervision works correctly for multiple dependent services on the host