| name | automated-updates |
| description | How NixOS hosts (devbox, cloudbox) automatically update self-packaged dependencies (currently just `beads`) via GitHub Actions and apply the resulting flake-locked changes via a systemd timer. Use when debugging update failures or understanding the update flow. |
Automated Updates
The devbox keeps dependencies up to date via GitHub Actions workflows and a systemd timer.
What Gets Updated
Local packages (daily)
- beads: Distributed issue tracker for AI workflows
Updated by .github/workflows/update-packages.yml using nix-update. Package definitions live in pkgs/<name>/default.nix.
How It Works
┌─────────────────────────────────────────────────────────────┐
│ GitHub Actions │
│ │
│ Local packages (daily): │
│ update-packages.yml → nix-update → PR → auto-merge │
│ │
│ CI (ci.yml) runs nix flake check on each PR │
│ ↓ │
│ Checks pass → PR auto-merges to main │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Devbox (systemd timer, every 4 hours) │
│ │
│ 1. pull-workstation.timer triggers │
│ 2. Fetches origin/main │
│ 3. If updates: git pull --ff-only │
│ 4. Runs: home-manager switch --flake .#dev │
└─────────────────────────────────────────────────────────────┘
Components
| Component | Location | Purpose |
|---|
ci.yml | .github/workflows/ | Runs nix flake check on PRs |
update-packages.yml | .github/workflows/ | Updates local packages via nix-update |
UPDATE_TOKEN | GitHub Secrets | PAT for PR creation + CI triggers |
pull-workstation | ~/.local/bin/ | Script to pull + apply home-manager |
pull-workstation.timer | systemd user | Triggers every 4h + 10min after boot |
home-manager-auto-expire.timer | systemd user | Cleans old generations daily |
Adding a New Package
- Create
pkgs/<name>/default.nix with the derivation
- Add to
localPkgsFor in flake.nix
- Reference as
localPkgs.<name> in home.base.nix
- Add
<name> to the matrix in .github/workflows/update-packages.yml
Checking Status
GitHub Side
gh run list --workflow=update-packages.yml --limit=5
gh pr list --label automated
gh pr checks <pr-number>
Devbox Side
systemctl --user status pull-workstation.timer
systemctl --user status home-manager-auto-expire.timer
systemctl --user list-timers
journalctl --user -u pull-workstation -n 50
journalctl --user -u home-manager-auto-expire -n 50
Manual Trigger
Trigger GitHub Update
gh workflow run update-packages.yml
gh workflow run update-packages.yml -f package=beads
Trigger Devbox Pull
~/.local/bin/pull-workstation
Or via systemd:
systemctl --user start pull-workstation
Troubleshooting
PR not being created
- Check workflow ran:
gh run list --workflow=update-packages.yml --limit=1
- Check for errors:
gh run view <run-id> --log
- Verify
UPDATE_TOKEN secret exists: gh secret list
PR not auto-merging
- Check CI passed:
gh pr checks <pr-number>
- Check auto-merge is enabled:
gh pr view <pr-number>
- Check branch protection: Settings → Branches → main
Devbox not pulling updates
- Check timer is active:
systemctl --user status pull-workstation.timer
- Check for dirty working tree:
git -C ~/projects/workstation status
- Check logs:
journalctl --user -u pull-workstation -n 50
- Manual test:
~/.local/bin/pull-workstation
"Working tree not clean" error
The pull script refuses to run if there are uncommitted changes:
cd ~/projects/workstation
git status
SSH errors in pull-workstation
The script uses BatchMode=yes which fails if:
- SSH key missing: Check
~/.ssh/id_ed25519_github exists
- Host key missing: Run
ssh -T git@github.com once manually
Old generations piling up
Check auto-expire is running:
systemctl --user status home-manager-auto-expire.timer
journalctl --user -u home-manager-auto-expire -n 20
Manual cleanup:
home-manager expire-generations "-7 days"
nix-collect-garbage
Configuration
Update Frequency
Local packages: Edit .github/workflows/update-packages.yml:
schedule:
- cron: '0 6 * * *'
Devbox timer: Edit users/dev/home.devbox.nix:
Timer = {
OnStartupSec = "10min";
OnUnitInactiveSec = "4h"; # Change to desired interval
};
Generation Retention
Edit users/dev/home.devbox.nix:
services.home-manager.autoExpire = {
frequency = "daily";
timestamp = "-7 days"; # Keep generations from last 7 days
};