Problem: after the wiki-hq reorg, agent-instruction and human-doc domains were still scattered across the repo root, with three now-redundant stub files cluttering it. The organizing principle wasn't visible in the layout. Change — enforce three clear buckets: - .agents/ = how agents operate: OIKOS.md, HERMES.md (moved from root), shared/ conventions, domains/ schemas, skills/, and operations/ (operator cheatsheet + enrollment + hermes-agent, moved from root). - knowledge/ = what exists + evidence: wiki/, GLOSSARY.md, and sources/ now including investigations/ (incident records are evidence/sources). - root = substrate + two entry points (AGENTS.md, README.md), plus plans/ as its own design-intent domain. Moves: - investigations/ -> knowledge/sources/investigations/ (incl. archive/, index). - operations/ -> .agents/operations/. - HERMES.md -> .agents/HERMES.md. - Deleted unreferenced root stubs CAVEMAN.md, CONTRIBUTING.md, and OIKOS.md (its 7 remaining linkers repointed to .agents/OIKOS.md). Consumers updated: - inventory.yaml doc_page (agent-enrollment) + regenerated hosts/*.yaml + cards. - tools/setup-hermes-soul.sh and bootstrap.sh (x2) -> .agents/HERMES.md. - bin/homelab help string -> .agents/operations/hermes-agent.md. - knowledge/operations schemas, llm-wiki, page-templates, incident-investigation skill, AGENTS.md/README nav -> new investigations/operations paths. - All markdown links rewritten via the path-resolving mapper. Left in place (substrate/executable/separate-domain): hosts/, ledger/, tools/, plans/, oikos/, mcp/, secrets/, bin/, inventory.yaml. Verification: docs-lint at baseline (2 intentional cross-repo refs, no new breakage); gen-topology.py --check exit 0; build_host_files.py idempotent; all doc_page targets resolve; Hermes provisioning scripts point at the new path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
10 KiB
mac-mini onboarding — post-mortem & lessons learned
Onboarded the mac-mini workstation (macOS Sequoia, arm64) into the hubris
homelab context system with the --with-hermes profile. What follows is a
chronological recap of every hitch, the fix, and the systemic improvements
needed so the next workstation takes 5 min instead of an hour.
Session log
Step 1 — clone + symlink
- Manually cloned
git.hubris.network/dtoro/Homelab-Docsto/Users/dtoro/Homelab-Docs. - Created
/opt/homelab-context→/Users/dtoro/Homelab-Docssymlink. - Lesson: bootstrap.sh was designed to do this from scratch, but we'd
already cloned by hand. The bootstrap's
clone exists; pullingpath handled it gracefully.
Step 2 — hostname mismatch
scutil --get LocalHostName→Davids-Mac-minihostname -s→Mac- Inventory file:
hosts/mac-mini.yaml - Fix:
sudo scutil --set LocalHostName mac-mini && sudo scutil --set HostName mac-mini - Lesson: The bootstrap and
homelab whoamiuse different hostname resolution. Bootstrap usesscutil --get LocalHostName(correct on macOS), but thehomelabCLI binary useshostname -s. Both need to match the inventory key. On a fresh macOS machine, neither does.
Step 3 — bootstrap dependencies
- pyyaml was missing →
pip install pyyaml - age and sops were missing →
brew install age sops - Netbird was already installed and connected ✓
- Lesson: The bootstrap preflight handles these, but only if running
bootstrap.shfrom the start. Since we ran it after manual setup, some steps (netbird install) were correctly skipped as already-present.
Step 4 — full bootstrap with --with-mcp --with-hermes
- Ran
sudo HOMELAB_GITEA_TOKEN=... bash bootstrap.sh --with-mcp --with-hermes - Age key issued ✓
- Launchd sync timer installed ✓
- Goose binary installed ✓
- Hermes CLI linked ✓
- MCP config merged ✓
refresh-credsskipped (not yet a recipient) ⚠️- Cosmetics:
chown: dtoro: illegal group nameat the end (benign, macOS group-naming quirk)
Step 5 — finalize from hubris
- Ran
homelab client add mac-mini --finalize-pubkey <age...> --with-hermeson hubris - Push failed:
[rejected] main -> main (fetch first)— hubris clone was stale, bootstrap had already pushed from mac-mini - Fix:
git pull --rebase && git pushon hubris - Lesson: bootstrap pushes remote changes before hubris can finalize,
creating a race. The
homelab client add --finalize-pubkeycommand should pull before committing/pushing.
Step 6 — sops couldn't find the age key
homelab secret hellofailed because sops looks in/Users/dtoro/.ssh/id_rsaetc. by default, not/etc/age/key.txt- The
homelabCLI re-execs viasudo -E env SOPS_AGE_KEY_FILE=... sops ..., but this requires passwordless sudo and the correct env var passthrough - Fix:
- Added NOPASSWD sudo rules
- Eventually
SOPS_AGE_KEYenv with the raw key content worked directly
- Lesson: Document the explicit
SOPS_AGE_KEY_FILEincantation in agent-enrollment troubleshooting. New clients can't assumehomelab secretworks out of the gate — the sudo re-exec chain has permission pitfall.
Step 7 — OpenRouter key was a placeholder
secrets/openrouter-api-key.yamlcontainedapi_key: PLACEHOLDER_REPLACE_WITH_REAL_OPENROUTER_KEY- User ran
sopson hubris, but got the same error (age key not found on hubris either —/root/.config/sops/age/keys.txtdidn't exist) - Fix:
SOPS_AGE_KEY_FILE=/etc/age/key.txt sops ...on hubris. Later: the user pasted the real key, but the sops file showedsk-or-...5c55— the literal content was truncated with ellipsis.
Step 8 — editor loaded the wrong data
- Neovim on the system is configured with
clipboard+=unnamedplus, which points*and+registers to the macOS clipboard manager rather than X11. When editing SOPS files, this caused the system clipboard to be pasted instead of the actual ciphertext. - This wasn't diagnosed during the session — the sops file would load empty or show the wrong content because the editor's idea of "paste" was disconnected from what sops expected.
- Fix: Run
sopswithEDITOR=nanoor another editor that doesn't hijack OS clipboards:EDITOR=nano SOPS_AGE_KEY_FILE=/etc/age/key.txt sops secrets/openrouter-api-key.yaml - Lesson: Add a strong warning to
hermes-agent.md/agent-enrollment.md: macOS neovim withclipboard+=unnamedplussilently breaks sops editing because the paste register reads from the system clipboard instead of the sops-managed buffer. UseEDITOR=nanoorEDITOR=vimwhen running sops interactively. Alternatively, override the clipboard option withEDITOR='nvim -c "set clipboard="'. - Also useful for the troubleshooting table in
agent-enrollment.mdunder a new row: "sops file loads empty / wrong content on macOS"
Step 9 — model doesn't support tool use
- Goose config pinned
nousresearch/hermes-4-405bvia OpenRouter - Error:
No endpoints found that support tool use - Fix: Switched to
deepseek/deepseek-v4-flashin~/.config/goose/config.yaml - Also updated
operations/hermes-agent.mdwith the correct model - Lesson: The default model in
bootstrap.shandhermes-agent.mdwas never validated on OpenRouter for tool-use capability. Need to either: (a) Pin a model known to work (deepseek/deepseek-v4-flash) (b) Or have the bootstrap probe OpenRouter at install time
Step 10 — MCP homelab extension returns 404
- Goose's homelab extension configured as
streamable_httpathttps://mcp.hubris.network/mcpreturns HTTP 404 - The actual MCP server runs on SSE (
/sse), not streamable_http - Known follow-up from
hermes-agent.md— server needs migration - Workaround: The agent works fine via the built-in
developerextension (shell + file) and thehomelabCLI
Step 11 — git credential dance
Several layers of issues with git authentication:
-
Directory permissions:
/etc/homelab-contextwas0700 root— dtoro couldn't access the credential file, and git'sstorehelper couldn't create its.lockfile.- Fix 1a:
sudo chmod 755 /etc/homelab-context - Fix 1b:
sudo chown -R dtoro:staff /etc/homelab-context
- Fix 1a:
-
macOS built-in osxkeychain: Apple's git has
osxkeychaincompiled in as a default credential helper. Even after configuring thestorehelper, git calls osxkeychain after every successfulget, which prompts for macOS keychain access.credential.helper = ""does NOT disable the compiled-in default- The
storehelper's.lockfile in/etc/homelab-context/also failed silently, causing fallback behaviour - Fix: Embed the credential in the remote URL directly:
https://dtoro:TOKEN@git.hubris.network/dtoro/Homelab-Docs.git - This bypasses all credential helpers entirely
-
refresh-creds: The credential is now managed by the remote URL. If the PAT is rotated,
homelab refresh-credswon't update the URL.- Workaround: Run
git remote set-url originafterrefresh-creds
- Workaround: Run
Step 12 — homelab CLI hostname detection
homelab whoamifailed withno hosts/Mac.yamlbecause the CLI useshostname -s(returningMac) while the bootstrap usesscutil --get LocalHostName(which we fixed tomac-mini)- Fix: Set both
LocalHostNameandHostNameviascutil - Lesson: The homelab CLI on macOS should prefer
scutil --get LocalHostNamelike the bootstrap does, or at least try both and pick the one that matches an inventory key. This is a CLI bug.
Improvement backlog
High priority
| # | Issue | Fix |
|---|---|---|
| 1 | Homelab CLI uses hostname -s on macOS; should use scutil --get LocalHostName to match bootstrap |
Patch bin/homelab to try scutil first, fall back to hostname -s |
| 2 | homelab client add --finalize-pubkey on hubris fails to push when remote is ahead (bootstrap pushes first) |
pull --rebase before committing in cmd_client_add |
| 3 | Default Goose model (nousresearch/hermes-4-405b) doesn't support tool use on OpenRouter |
Update bootstrap.sh default and hermes-agent.md to deepseek/deepseek-v4-flash |
| 4 | MCP server needs streamable_http migration | Follow-up #1 from hermes-agent.md — FastMCP transport="sse" → transport="streamable_http" |
| 5 | homelab refresh-creds should also update embedded remote URLs |
In cmd_refresh_creds, after writing the credential file, update any remote URL that has an embedded credential |
Medium priority
| # | Issue | Fix |
|---|---|---|
| 6 | macOS neovim with clipboard+=unnamedplus breaks sops editing |
Add troubleshooting row to agent-enrollment.md; recommend EDITOR=nano |
| 7 | /etc/homelab-context directory with 0700 root permissions blocks non-root git |
Change to 755 in bootstrap.sh on all OSes (or at least macOS) |
| 8 | Bootstrap chown at end gives illegal group name on macOS |
Fix group detection in bootstrap.sh for macOS |
| 9 | homelab secret re-exec via sudo chain is fragile — needs passwordless sudo or TTY |
Consider SOPS_AGE_KEY env-var fallback path in the CLI itself |
Low priority
| # | Issue | Fix |
|---|---|---|
| 10 | Onboarding this machine revealed no HERMES.md file in the repo |
Create the persona file for the Goose hints symlink |
| 11 | Git credential store helper lock mechanism is OS-sensitive and fragile |
Document embedded-URL pattern as the preferred approach for workstations |
| 12 | AGENTS.md references /opt/homelab-context/hosts/<hostname>.yaml but the canonical path is now a symlink |
Verify the path resolution edge cases |
Changelog
2026-06-01 — initial post-mortem
Captured the full onboarding of mac-mini into the hubris homelab context system, including the hostname mismatch, sudo/sops credential chain, model selection, git credential gymnastics, and editor clipboard interference.
2026-06-02 — MCP server migrated to streamable-http
Item #4 resolved. FastMCP server now uses transport="streamable-http" (hyphen,
not underscore), serving at https://mcp.hubris.network/mcp. All doc references
and client configs (Goose, bootstrap.sh, agent-enrollment.md) updated. Service
re-deployed on apps LXC (105).