Add documentation for:
- --debug flag in Listener Flags table
- --heartbeat-interval flag (was missing)
- extraArgs NixOS module option
- New Troubleshooting section with debug logging examples
and guidance for diagnosing metrics issues
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a --debug flag to the listener command that enables debug-level
logging. When enabled, the listener logs detailed information about
metrics recording including:
- When deployment start/end metrics are recorded
- The action, success status, and duration being recorded
- Whether metrics are enabled or disabled (skipped)
This helps troubleshoot issues where deployment metrics appear to
remain at zero after deployments.
Also add extraArgs option to the NixOS module to allow passing
additional arguments like --debug to the service.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The existing tests for RecordDeploymentEnd and RecordDeploymentFailure
only verified the counter was incremented, not that the histogram was
updated with duration observations. Add histogram verification to:
- TestCollector_RecordDeploymentEnd_Success
- TestCollector_RecordDeploymentEnd_Failure
- TestCollector_RecordDeploymentFailure
Also add listener tests to verify metrics are properly initialized when
MetricsEnabled is true and that the recording functions work correctly
in the context of deployment handling.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After a successful switch deployment, the listener now waits for Prometheus
to scrape the /metrics endpoint before exiting for restart. This ensures
deployment metrics are captured before the process restarts and resets
in-memory counters. Falls back to a 60 second timeout if no scrape occurs.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Counter and histogram metrics were absent from Prometheus scrapes until
the first deployment occurred, making it impossible to distinguish
"no deployments" from "exporter not running" in dashboards and alerts.
Initialize all expected label combinations with zero values when the
collector is created so metrics appear in every scrape from startup.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The CLI was reporting deployment failures even when the listener showed
success. This was a race condition: after a successful switch deployment,
the listener would send the "completed" response then immediately signal
restart. The NATS connection closed before the buffered message was
actually sent to the broker, so the CLI never received it.
Adding Flush() after sending the completed response ensures the message
reaches NATS before the listener can exit.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Send periodic "running" status messages while nixos-rebuild executes,
preventing the idle timeout from triggering before deployments complete.
This fixes false "Some deployments failed" warnings in MCP when builds
take longer than 30 seconds.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add an optional Prometheus metrics HTTP endpoint to the listener for
monitoring deployment operations. Includes four metrics:
- homelab_deploy_deployments_total (counter with status/action/error_code)
- homelab_deploy_deployment_duration_seconds (histogram with action/success)
- homelab_deploy_deployment_in_progress (gauge)
- homelab_deploy_info (gauge with hostname/tier/role/version)
New CLI flags: --metrics-enabled, --metrics-addr (default :9972)
New NixOS options: metrics.enable, metrics.address, metrics.openFirewall
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a list-hosts command that mirrors the MCP list_hosts functionality,
allowing discovery of available deployment targets from the command line.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous hardening options (ProtectControlGroups, LockPersonality,
SystemCallArchitectures, etc.) prevented Nix from creating the kernel
namespaces required for build sandboxing. Following the approach of
the NixOS auto-upgrade module which has no hardening since nixos-rebuild
requires broad system access.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The PrivateDevices=true systemd hardening option was preventing Nix
from creating the kernel namespaces required for its build sandbox.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The CLI was incorrectly reporting "some deployments failed" even when
deployments succeeded. This was because AllSucceeded() checked if every
response had StatusCompleted, but the Responses slice contains all
messages including intermediate ones like "started". Since started !=
completed, it returned false.
Now AllSucceeded() only examines final responses (using IsFinal()) and
checks that each host's final status is completed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After a successful switch deployment, the listener now exits gracefully
so systemd can restart it with the new binary. This works together with
stopIfChanged/restartIfChanged to ensure deployments complete before
the service restarts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add stopIfChanged and restartIfChanged options to prevent the listener
from being interrupted when nixos-rebuild switch activates a new
configuration that changes the service definition.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The listener service had ProtectHome=read-only which prevented Nix
from writing to /root/.cache when fetching git flakes. This adds a
CacheDirectory managed by systemd and sets XDG_CACHE_HOME to use it.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add nixos-rebuild to listener service PATH in NixOS module
- Fix CLI deploy command hanging after receiving final status by properly
tracking lastResponse time and exiting when all hosts have responded
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of requiring users to provide the package via overlay,
the module now receives `self` from the flake and uses the
package directly from `self.packages`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the complete subject hierarchy including deploy subjects,
response subjects, and discovery subject. Add example NATS server
configuration demonstrating tiered authentication with listener,
test deployer, and admin deployer permission patterns.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allows setting --nats-url, --nkey-file, --branch, --action, and --timeout
via HOMELAB_DEPLOY_* environment variables.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reject NKey files that are readable by group or others (permissions
more permissive than 0600). This prevents accidental exposure of
private keys through overly permissive file permissions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use builtins.match to parse version from cmd/homelab-deploy/main.go
so only one location needs updating when bumping versions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add github.com/google/uuid to dependencies list
- Fix version bumping: both main.go and flake.nix need updates
- Add section on updating vendorHash when dependencies change
- Use nix run .#default instead of nix build for verification
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document all three operational modes, CLI flags, MCP tools,
NixOS module options, and the message protocol.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement the complete homelab-deploy system with three operational modes:
- Listener mode: Runs on NixOS hosts as a systemd service, subscribes to
NATS subjects with configurable templates, executes nixos-rebuild on
deployment requests with concurrency control
- MCP mode: MCP server exposing deploy, deploy_admin, and list_hosts
tools for AI assistants with tiered access control
- CLI mode: Manual deployment commands with subject alias support via
environment variables
Key components:
- internal/messages: Request/response types with validation
- internal/nats: Client wrapper with NKey authentication
- internal/deploy: Executor with timeout and lock for concurrency
- internal/listener: Subject template expansion and request handling
- internal/cli: Deploy logic with alias resolution
- internal/mcp: MCP server with mcp-go integration
- nixos/module.nix: NixOS module with hardened systemd service
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add configurable NATS subject patterns with template variables
(<hostname>, <tier>, <role>) for multi-tenant setups
- Add deploy.discover subject for host discovery
- Simplify CLI to use direct subjects with optional aliases via
HOMELAB_DEPLOY_ALIAS_* environment variables
- Clarify request/reply flow with UUID-based response subjects
- Expand NixOS module with hardening options, package option,
and configurable deploy/discover subjects
- Switch CLI framework from cobra to urfave/cli/v3
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add CLAUDE.md with project guidance for Claude Code including
architecture overview, build commands, and testing procedures.
Update flake.nix with proper Go development shell (go, gopls,
gotools, golangci-lint, govulncheck, delve) and buildGoModule
package definition.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>