fix: rename Homelab-Docs → oikos across all active files; add public enrollment route
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled

This commit is contained in:
2026-07-08 11:46:42 +02:00
parent e148c7a981
commit ca16b75b90
12 changed files with 58 additions and 30 deletions

View File

@@ -81,7 +81,7 @@ If DNS isn't an option at all, override the URLs at bootstrap time:
```bash
sudo HOMELAB_GITEA_TOKEN=... \
HOMELAB_REPO_URL=http://192.168.8.121:3000/dtoro/Homelab-Docs.git \
HOMELAB_REPO_URL=http://192.168.8.121:3000/dtoro/oikos.git \
HOMELAB_ISSUANCE_NETBIRD=http://192.168.8.205:9820/issue \
HOMELAB_MCP_URL=http://192.168.8.205:9810/mcp \
bash /tmp/bootstrap.sh --with-mcp
@@ -129,7 +129,7 @@ TOKEN=... # your Gitea PAT, scope read:repository
# Fetch bootstrap.sh from gitea (HTTPS uses split-DNS → caddy).
curl -fsSL -u "dtoro:$TOKEN" \
https://git.hubris.network/dtoro/Homelab-Docs/raw/branch/main/bootstrap.sh \
https://git.hubris.network/dtoro/oikos/raw/branch/main/bootstrap.sh \
-o /tmp/bootstrap.sh
# Run it.
@@ -333,7 +333,7 @@ The CLI prints a follow-up checklist that the operator must do manually:
| --- | --- | --- |
| `no hosts/<hostname>.yaml in the repo` | Hostname doesn't match inventory entry | Rename either side (see above) |
| `fatal: could not read Username for 'http://192.168.8.121:3000'` | bootstrap.sh's credentials file has wrong scheme | Fixed in commit `de6f8be`; pull latest `bootstrap.sh` |
| `gnutls_handshake() failed: TLS connection was non-properly terminated` cloning `git.hubris.network` | Client DNS resolves `*.hubris.network` to the public VPS IP | Configure split-DNS (LXC 180 / Netbird forwarder) or `/etc/hosts` override; or use `HOMELAB_REPO_URL=http://192.168.8.121:3000/dtoro/Homelab-Docs.git` |
| `gnutls_handshake() failed: TLS connection was non-properly terminated` cloning `git.hubris.network` | Client DNS resolves `*.hubris.network` to the public VPS IP | Configure split-DNS (LXC 180 / Netbird forwarder) or `/etc/hosts` override; or use `HOMELAB_REPO_URL=http://192.168.8.121:3000/dtoro/oikos.git` |
| `TLS/SSL connection has been closed (EOF)` connecting MCP | Same — `mcp.hubris.network` resolves to public VPS without this vhost | Same DNS fix |
| `Invalid Host header` from MCP server | FastMCP's DNS-rebinding protection (default whitelist is 127.0.0.1 only) | Fixed in commit `6848640`; pull latest `mcp/server.py` and redeploy |
| `python3-yaml` install fails on Fedora | Wrong package name | Use `python3-pyyaml` (Fedora) instead of `python3-yaml` (Debian) |

View File

@@ -36,7 +36,7 @@ homelab client add new-machine
# 3. On new-machine: bootstrap with --with-hermes.
TOKEN=... # gitea PAT, read:repository
curl -fsSL -u "dtoro:$TOKEN" \
https://git.hubris.network/dtoro/Homelab-Docs/raw/branch/main/bootstrap.sh \
https://git.hubris.network/dtoro/oikos/raw/branch/main/bootstrap.sh \
-o /tmp/bootstrap.sh
sudo HOMELAB_GITEA_TOKEN=$TOKEN bash /tmp/bootstrap.sh --with-mcp --with-hermes

1
.gitignore vendored
View File

@@ -8,6 +8,7 @@ oikos/state.json
# Compiled binaries (Go rewrite — bin/oikos, bin/hermes)
bin/oikos
bin/hermes
oikos/oikos
# Legacy Python oikos (superseded by cmd/oikos Go binary — Phase 1-6 rewrite).
# oikos/ kernel files are still imported by bin/homelab for operational CLI

View File

@@ -37,7 +37,7 @@ via the Oikos API.
To enroll:
```bash
# Run from any machine with mesh connectivity
curl -fsSL https://git.hubris.network/dtoro/Homelab-Docs/raw/main/bootstrap.sh | sudo bash
curl -fsSL https://git.hubris.network/dtoro/oikos/raw/main/bootstrap.sh | sudo bash
# Or with optional tooling:
curl ... | sudo bash -s -- --with-mcp # wire Claude's MCP config

View File

@@ -8,7 +8,7 @@
# context poller replaces the old 5-minute git pull.
#
# Usage:
# curl -fsSL https://git.hubris.network/dtoro/Homelab-Docs/raw/main/bootstrap.sh \
# curl -fsSL https://git.hubris.network/dtoro/oikos/raw/main/bootstrap.sh \
# | sudo bash
# curl ... | sudo bash -s -- --with-mcp # wire Claude's .mcp.json
# curl ... | sudo bash -s -- --with-hermes # install Goose + Hermes
@@ -24,7 +24,7 @@
set -euo pipefail
# ── defaults ─────────────────────────────────────────────────────────
REPO_RAW_URL="${HOMELAB_RAW_URL:-https://git.hubris.network/dtoro/Homelab-Docs/raw/main}"
REPO_RAW_URL="${HOMELAB_RAW_URL:-https://git.hubris.network/dtoro/oikos/raw/main}"
OIKOS_API_URL="${HOMELAB_OIKOS_URL:-https://oikos.hubris.network/api/v1}"
CLONE_DIR="${HOMELAB_CONTEXT_DIR:-/opt/homelab}"
MCP_URL="${HOMELAB_MCP_URL:-https://mcp.hubris.network/mcp}"
@@ -171,6 +171,14 @@ for tmpl in git_log.txt git_status.txt test_results.txt; do
fi
done
# ── detect control-plane (use localhost if API is reachable directly) ─
if [ -z "${HOMELAB_OIKOS_URL:-}" ]; then
if curl -s --connect-timeout 2 http://localhost:8090/api/v1/health >/dev/null 2>&1; then
OIKOS_API_URL="http://localhost:8090/api/v1"
log "API reachable on localhost, using direct connection"
fi
fi
# ── enroll via Oikos API (replaces archived Python secrets-issuance) ─
log "enrolling via Oikos API..."

View File

@@ -94,6 +94,25 @@ func NewHandler(ctx context.Context, pool *db.Pool, cfg config.Config) http.Hand
w.Write([]byte(`{"status":"ok"}`))
})
// Client enrollment — unauthenticated (IP-gated in handler).
// Registered on base router BEFORE HandlerWithOptions so it
// bypasses the combinedAuth middleware applied to all /api/v1/*.
r.Post("/api/v1/clients/enroll", func(w http.ResponseWriter, req *http.Request) {
var body gen.EnrollRequest
if err := json.NewDecoder(req.Body).Decode(&body); err != nil {
writeProblem(w, req, http.StatusBadRequest, "invalid request body", err.Error())
return
}
resp, err := s.EnrollClient(req.Context(), gen.EnrollClientRequestObject{Body: &body})
if err != nil {
writeProblemFromErr(w, req, err)
return
}
if err := resp.VisitEnrollClientResponse(w); err != nil {
writeProblem(w, req, http.StatusInternalServerError, "response encoding failed", err.Error())
}
})
strict := gen.NewStrictHandlerWithOptions(s, nil, gen.StrictHTTPServerOptions{
RequestErrorHandlerFunc: func(w http.ResponseWriter, req *http.Request, err error) {
writeProblem(w, req, http.StatusBadRequest, "bad request", err.Error())

View File

@@ -139,7 +139,7 @@ services:
public_host: mcp.hubris.network
endpoint: https://mcp.hubris.network/mcp
doc_page: knowledge/wiki/infrastructure/homelab-context.md
config_repo: dtoro/Homelab-Docs
config_repo: dtoro/oikos
note: MCP server. Read-only context + management. Reachable on the LAN via Caddy
and from off-LAN via Netbird (192.168.8.0/24 is a network resource routed through
hubris).
@@ -151,7 +151,7 @@ services:
public_host: secrets.hubris.network
endpoint: https://secrets.hubris.network/issue
doc_page: .agents/operations/agent-enrollment.md
config_repo: dtoro/Homelab-Docs
config_repo: dtoro/oikos
note: Issues per-client age private keys. Gated at source-IP layer (mesh + LAN
subnets in MESH_SUBNETS).
risk_notes: identity issuance — any change is security-sensitive; key operations are destructive-class

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# Oikos deploy script — triggered by Gitea webhook on push to dtoro/Homelab-Docs.
# Oikos deploy script — triggered by Gitea webhook on push to dtoro/oikos.
# Runs on mac-mini as non-root user via systemd unit oikos-deploy-webhook.service.
# Phase 6: CI-gated, SHA-tagged images, rolling restart, pre-deploy pg_dump.

View File

@@ -289,7 +289,7 @@ entities:
- {slug: "repo:mule-image", type: config-repo, name: dtoro/mule-image}
- {slug: "repo:artifacto", type: config-repo, name: dtoro/Artifacto}
- {slug: "repo:terminalito", type: config-repo, name: dtoro/terminalito}
- {slug: "repo:homelab-docs", type: config-repo, name: dtoro/Homelab-Docs}
- {slug: "repo:homelab-docs", type: config-repo, name: dtoro/oikos}
# ─── Ingress routes (Caddy, *.hubris.network) ──────────────────────
- {slug: "ingress:proxmox.hubris.network", type: ingress-route, name: proxmox.hubris.network}

View File

@@ -137,7 +137,7 @@ documents:
\ Rejected. |\n| **SMB on host** | Same host-blast-radius problem, plus 3050% lower throughput than NFS on Linux↔Linux.\
\ Rejected. |\n| **NFS in a dedicated LXC** ← this | Within ~2% of host performance (LXC is namespace isolation; IO path\
\ is unchanged), zero new daemons on hubris, matches the existing fleet pattern. Selected. |\n\nRationale lives in [the\
\ install plan](https://git.hubris.network/dtoro/Homelab-Docs) `/root/.claude/plans/i-wannt-you-to-nifty-muffin.md` on\
\ install plan](https://git.hubris.network/dtoro/oikos) `/root/.claude/plans/i-wannt-you-to-nifty-muffin.md` on\
\ hubris.\n\n## Operations\n\n- **Reload exports** after editing `/etc/exports`: `pct exec 102 -- exportfs -ra`\n- **List\
\ active exports:** `pct exec 102 -- exportfs -v`\n- **Watch from outside:** `showmount -e 192.168.8.200`\n- **Service\
\ health:** `pct exec 102 -- systemctl is-active nfs-server rpcbind`\n- **Restart cleanly:** `pct restart 102` (ZimaOS\
@@ -392,7 +392,7 @@ documents:
\ The Go MCP uses the official MCP Go SDK (Streamable HTTP, not\n> FastMCP) with 15 tools including `get_blast_radius`,\
\ `request_execution`, and\n> `get_agent_activity`. Source: `internal/mcp/server.go`.\n\n**Current (Python) implementation\
\ — DO NOT MODIFY, awaiting cutover:**\nFastMCP server (Python venv at `/opt/homelab-mcp/.venv`). Reads from\n`/opt/homelab-context/`\
\ (this LXC is itself an enrolled\n[homelab-context](../infrastructure/homelab-context.md) client). Source\nis `dtoro/Homelab-Docs/mcp/server.py`;\
\ (this LXC is itself an enrolled\n[homelab-context](../infrastructure/homelab-context.md) client). Source\nis `dtoro/oikos/mcp/server.py`;\
\ service unit\n`homelab-mcp.service` binds `0.0.0.0:9810`. DNS-rebinding protection\ndisabled at the FastMCP layer because\
\ mesh+LAN gating is the actual\ntrust boundary.\n\n- Endpoint: `https://mcp.hubris.network/mcp` (Caddy → `:9810`). StreamableHTTP\
\ transport (POST `/mcp`).\n- 14 tools registered: `get_host`, `list_services`, `find_service`,\n `get_topology`, `search_docs`,\
@@ -400,7 +400,7 @@ documents:
\ `get_lxc_state`, `ping_service` (read-only management).\n- Management tools shell out via SSH using a dedicated `mcp-reader`\
\ key\n (planned; not provisioned yet — management tools fail until then).\n\n#### Auto-deploy pipeline (homelab-mcp)\n\
Receiver at `/opt/homelab-mcp/mcp/deploy/webhook/` (in-tree alongside\nthe server code). Listens on `0.0.0.0:9811`, secret\
\ in\n`/etc/homelab-mcp-deploy/secret`, systemd unit\n`homelab-mcp-deploy.service`. Gitea webhook id 10 on\n`dtoro/Homelab-Docs`.\
\ in\n`/etc/homelab-mcp-deploy/secret`, systemd unit\n`homelab-mcp-deploy.service`. Gitea webhook id 10 on\n`dtoro/oikos`.\
\ Deploy script reinstalls the service unit and\nrestarts on push.\n\n### secrets-issuance (`/opt/secrets-issuance/`)\
\ — DEPRECATED (Go Phase 5)\n\n> **Status:** Replaced by `internal/secrets/` in the Go rewrite. Machine identities\n>\
\ are now managed via Infisical (`docker compose --profile infisical up`).\nTiny HTTP service that issues per-client age\
@@ -3917,15 +3917,15 @@ documents:
\ |\n| `dtoro/claudio-bot` | ~~[claudio-bot (123)](../containers/archive/123-claudio-bot.md)~~ (destroyed\
\ 2026-06-04) | ⊘ | `http://192.168.8.230:9797/deploy` (dead) | (archived) | Repo archived — LXC destroyed |\n| `dtoro/backup-library`\
\ | [hubris host](../hosts/hubris.md) `/opt/backup-library/` | A | `http://192.168.8.77:9798/deploy` | (orig)\
\ | runs `deploy.sh` (preserves admin-edited `/etc/restic/include-*.list`) |\n| `dtoro/Homelab-Docs` → homelab-mcp | [apps\
\ | runs `deploy.sh` (preserves admin-edited `/etc/restic/include-*.list`) |\n| `dtoro/oikos` → homelab-mcp | [apps\
\ (105)](../containers/105-apps.md) `/opt/homelab-mcp/` | B | `http://192.168.8.205:9811/deploy` | 10 (deprecated) | ~~reinstalls\
\ `homelab-mcp.service` + restart~~ → replaced by Go Docker stack on mac-mini |\n| `dtoro/Homelab-Docs` → secrets-issuance\
\ `homelab-mcp.service` + restart~~ → replaced by Go Docker stack on mac-mini |\n| `dtoro/oikos` → secrets-issuance\
\ | [apps (105)](../containers/105-apps.md) `/opt/secrets-issuance/` | B | `http://192.168.8.205:9821/deploy` | 11 (deprecated)\
\ | ~~reinstalls `secrets-issuance.service` + restart~~ → replaced by `internal/secrets/` Go package |\n| `dtoro/terminalito`\
\ | [trmnl (128)](../containers/128-trmnl.md) `/opt/terminalito/` | B | `http://192.168.8.211:9797/deploy`\
\ | 12 | reinstalls units + `systemctl restart trmnl-plugins` |\n| `dtoro/Homelab-Docs` → oikos-console | [apps (105)](../containers/105-apps.md)\
\ | 12 | reinstalls units + `systemctl restart trmnl-plugins` |\n| `dtoro/oikos` → oikos-console | [apps (105)](../containers/105-apps.md)\
\ `/opt/oikos-console/` | B | `http://192.168.8.205:9831/deploy` | 14 | reinstalls `oikos-console.service` + restart —\
\ see [oikos/console/deploy/README.md](../../../oikos/console/deploy/README.md) |\n\n> Note: `dtoro/Homelab-Docs` has\
\ see [oikos/console/deploy/README.md](../../../oikos/console/deploy/README.md) |\n\n> Note: `dtoro/oikos` has\
\ **three webhooks** firing on the same push.\n> Each owns its own clone on LXC 105. They don't conflict because each\n\
> deploy.sh only touches its own service unit + venv.\n\n> **Not yet wired:** `dtoro/claudio-monitor` (push, then `/opt/claudio-monitor/scripts/deploy.sh`\
\ manually). The former authentik LXC (124) is destroyed — Authentik runs on the [VPS](../../../hosts/netbird-vps.yaml).\
@@ -3934,7 +3934,7 @@ documents:
\ ↔ `dtoro/gitea-customizations` (auto-deploys)\n- `/opt/artifacto/` ↔ `dtoro/Artifacto` (auto-deploys)\n- `/opt/mule-image/`\
\ ↔ `dtoro/mule-image` (auto-deploys)\n- ~~`/opt/plato/app/` ↔ `dtoro/Plato`~~ (destroyed 2026-06-28)\n- ~~`/opt/claudio-bot/`\
\ ↔ `dtoro/claudio-bot`~~ (destroyed 2026-06-04)\n- `/opt/backup-library/` ↔ `dtoro/backup-library` (auto-deploys)\n-\
\ `/opt/homelab-mcp/` + `/opt/secrets-issuance/` ↔ `dtoro/Homelab-Docs` (auto-deploys both, see [homelab-context](homelab-context.md))\n\
\ `/opt/homelab-mcp/` + `/opt/secrets-issuance/` ↔ `dtoro/oikos` (auto-deploys both, see [homelab-context](homelab-context.md))\n\
\n## Per-pipeline notes / gotchas\n\n### caddy-conf\n- Repo includes `scripts/webhook/install.sh`. Editing the systemd\
\ unit *inside the repo* does **not** auto-reinstall — re-run `install.sh` manually after unit edits.\n- The unit has\
\ `ReadWritePaths=/etc/caddy` — load-bearing (`ProtectSystem=full` would otherwise block `git pull`).\n\n### gitea-customizations\n\
@@ -3950,7 +3950,7 @@ documents:
\ auth (not bearer), so cleanup couldn't be automated.\n\n### backup-library\n- Currently the only deploy that targets\
\ the host directly (`192.168.8.77:9798`).\n- `deploy.sh` is careful to preserve admin edits to `/etc/restic/include-*.list`\
\ — canonical source is `config/` in the repo, but the install path is treated as authoritative once `deploy.sh` has run.\n\
\n### homelab-mcp / secrets-issuance\n- Both ride a single push to `dtoro/Homelab-Docs`. Two clones on LXC 105\n (`/opt/homelab-mcp`,\
\n### homelab-mcp / secrets-issuance\n- Both ride a single push to `dtoro/oikos`. Two clones on LXC 105\n (`/opt/homelab-mcp`,\
\ `/opt/secrets-issuance`) — each is an independent\n Shape-B target with its own webhook receiver.\n- The deploy script\
\ restarts the service it just updated. Because the\n webhook receiver itself is a separate systemd unit (`*-deploy.service`),\n\
\ it does NOT restart itself — but `deploy.sh` running `systemctl\n restart homelab-mcp-deploy.service` (or the secrets-issuance\
@@ -3981,7 +3981,7 @@ documents:
\ on [trmnl (128)](../containers/128-trmnl.md). Shape B (`server/deploy/webhook.py` receiver, in-repo `server/deploy/deploy.sh`;\
\ secret `/etc/terminalito-deploy/secret`). `app.ini` `ALLOWED_HOST_LIST` extended with `192.168.8.211`. Verified end-to-end\
\ with a push. Repo-local `credential.helper` in `/opt/terminalito/.git/config` (the unit can't read root's global git\
\ config).\n\n### 2026-05-20 — homelab-mcp + secrets-issuance pipelines added\nWebhook ids 10 + 11 on `dtoro/Homelab-Docs`\
\ config).\n\n### 2026-05-20 — homelab-mcp + secrets-issuance pipelines added\nWebhook ids 10 + 11 on `dtoro/oikos`\
\ (ports `9811` + `9821` on [apps (105)](../containers/105-apps.md)). Two webhooks on one repo — each owns its own clone\
\ (`/opt/homelab-mcp`, `/opt/secrets-issuance`) and only restarts its own service. See [homelab-context](homelab-context.md)\
\ for why both services live in one repo.\n\n### 2026-05-13 — Plato pipeline added\nWebhook id 8 on `dtoro/Plato` (port\
@@ -4008,7 +4008,7 @@ documents:
in `/opt/terminalito/.git/config` (the unit can't read root's global git config).
- date: '2026-05-20'
title: homelab-mcp + secrets-issuance pipelines added
body: Webhook ids 10 + 11 on `dtoro/Homelab-Docs` (ports `9811` + `9821` on [apps (105)](../containers/105-apps.md)).
body: Webhook ids 10 + 11 on `dtoro/oikos` (ports `9811` + `9821` on [apps (105)](../containers/105-apps.md)).
Two webhooks on one repo — each owns its own clone (`/opt/homelab-mcp`, `/opt/secrets-issuance`) and only restarts its
own service. See [homelab-context](homelab-context.md) for why both services live in one repo.
- date: '2026-05-13'
@@ -4531,7 +4531,7 @@ documents:
Code, Hermes Agent, future MCP-capable clients) on every machine in the lab\nself-locating and able to read the same source\
\ of truth.\n\nOperational walkthrough for enrolling a new client lives in\n[operations/agent-enrollment.md](../../../.agents/operations/agent-enrollment.md);\
\ this\npage is the architecture reference.\n\n## What's where\n\n| Piece | Host | Path | Role |\n| --- | --- | --- |\
\ --- |\n| Source of truth | [gitea (104)](../containers/104-gitea.md) | `dtoro/Homelab-Docs.git` | Inventory + wiki +\
\ --- |\n| Source of truth | [gitea (104)](../containers/104-gitea.md) | `dtoro/oikos.git` | Inventory + wiki +\
\ service code |\n| Per-client clone | every enrolled client | `/opt/homelab-context/` | Read by `homelab` CLI, MCP server,\
\ Hermes Agent |\n| `homelab` CLI | every enrolled client | `/usr/local/bin/homelab` → `/opt/homelab-context/bin/homelab`\
\ (symlink) | Operator surface for enroll/secret/ssh/pct |\n| Per-client age key | every enrolled client | `/etc/age/key.txt`\
@@ -4541,10 +4541,10 @@ documents:
\ | `secrets-issuance.service` on port 9820 (https://secrets.hubris.network/issue) | Generates per-client age keypair\
\ on first bootstrap; idempotent; admin-token-gated `/revoke` |\n| Sync timer | every enrolled client | `homelab-context-sync.timer`\
\ (Linux) / `network.hubris.homelab-context-sync.plist` (macOS) | `git pull --ff-only` every 5 min |\n| Encrypted secrets\
\ | `dtoro/Homelab-Docs` | `secrets/*.yaml` (SOPS+age) | Recipients declared in `.sops.yaml` |\n| Read-only context PAT\
\ | `dtoro/oikos` | `secrets/*.yaml` (SOPS+age) | Recipients declared in `.sops.yaml` |\n| Read-only context PAT\
\ | `dtoro` Gitea user, scope `read:repository` | given to operators out-of-band | Bootstrap-only — for the initial clone\
\ before SOPS works |\n| Write-scoped PAT | `secrets/gitea-pat.yaml` (SOPS) | `homelab refresh-creds` swaps it into `/etc/homelab-context/git-credentials`\
\ | All post-bootstrap pushes (client lifecycle, wiki edits) |\n\n## Data flow\n\n```\n dtoro/Homelab-Docs\
\ | All post-bootstrap pushes (client lifecycle, wiki edits) |\n\n## Data flow\n\n```\n dtoro/oikos\
\ (gitea)\n │\n ┌────────── push ────────┤ ◀── git push (write PAT or SSH)\n \
\ │ │\n │ ┌────── push ──────┘\n │ │ │\n │ │ \
\ ▼ webhook (push event)\n │ │ ┌─── homelab-mcp-deploy ──── (LXC 105:9811)\n │ \
@@ -5936,8 +5936,8 @@ investigations:
content: "# mac-mini onboarding — post-mortem & lessons learned\n\nOnboarded the `mac-mini` workstation (macOS Sequoia,\
\ arm64) into the hubris\nhomelab context system with the `--with-hermes` profile. What follows is a\nchronological recap\
\ of every hitch, the fix, and the systemic improvements\nneeded so the next workstation takes 5 min instead of an hour.\n\
\n## Session log\n\n### Step 1 — clone + symlink\n- Manually cloned `git.hubris.network/dtoro/Homelab-Docs` to `/Users/dtoro/Homelab-Docs`.\n\
- Created `/opt/homelab-context` → `/Users/dtoro/Homelab-Docs` symlink.\n- **Lesson:** bootstrap.sh was designed to do\
\n## Session log\n\n### Step 1 — clone + symlink\n- Manually cloned `git.hubris.network/dtoro/oikos` to `/Users/dtoro/oikos`.\n\
- Created `/opt/homelab-context` → `/Users/dtoro/oikos` symlink.\n- **Lesson:** bootstrap.sh was designed to do\
\ this from scratch, but we'd\n already cloned by hand. The bootstrap's `clone exists; pulling` path handled\n it gracefully.\n\
\n### Step 2 — hostname mismatch\n- `scutil --get LocalHostName` → `Davids-Mac-mini`\n- `hostname -s` → `Mac`\n- Inventory\
\ file: `hosts/mac-mini.yaml`\n- **Fix:** `sudo scutil --set LocalHostName mac-mini && sudo scutil --set HostName mac-mini`\n\
@@ -5990,7 +5990,7 @@ investigations:
\ as a default credential helper. Even after configuring the `store` helper,\n git calls osxkeychain after every successful\
\ `get`, which prompts for\n macOS keychain access.\n - `credential.helper = \"\"` does NOT disable the compiled-in\
\ default\n - The `store` helper's `.lock` file in `/etc/homelab-context/` also failed\n silently, causing fallback\
\ behaviour\n - **Fix:** Embed the credential in the remote URL directly:\n `https://dtoro:TOKEN@git.hubris.network/dtoro/Homelab-Docs.git`\n\
\ behaviour\n - **Fix:** Embed the credential in the remote URL directly:\n `https://dtoro:TOKEN@git.hubris.network/dtoro/oikos.git`\n\
\ - This bypasses all credential helpers entirely\n\n3. **refresh-creds:** The credential is now managed by the remote\
\ URL.\n If the PAT is rotated, `homelab refresh-creds` won't update the URL.\n - **Workaround:** Run `git remote\
\ set-url origin` after `refresh-creds`\n\n### Step 12 — `homelab` CLI hostname detection\n- `homelab whoami` failed with\

View File

@@ -9,7 +9,7 @@ set -euo pipefail
OIKOS_URL="${OIKOS_API_URL:-https://oikos.hubris.network/api/v1}"
HNAME=$(scutil --get LocalHostName 2>/dev/null || hostname -s)
CONTEXT_DIR="${HOMELAB_CONTEXT_DIR:-/opt/homelab}"
RAW_URL="${HOMELAB_RAW_URL:-https://git.hubris.network/dtoro/Homelab-Docs/raw/main}"
RAW_URL="${HOMELAB_RAW_URL:-https://git.hubris.network/dtoro/oikos/raw/main}"
STATE_FILE="$CONTEXT_DIR/.context_since"
SINCE=""

View File

@@ -17,7 +17,7 @@ if command -v realpath &>/dev/null; then
elif command -v grealpath &>/dev/null; then
REPO_REAL=$(grealpath "$CONTEXT_DIR")
else
REPO_REAL=$(perl -e 'print Cwd::abs_path(shift)' "$CONTEXT_DIR" 2>/dev/null || echo "/Users/dtoro/Homelab-Docs")
REPO_REAL=$(perl -e 'print Cwd::abs_path(shift)' "$CONTEXT_DIR" 2>/dev/null || echo "/Users/dtoro/oikos")
fi
REPO_OWNER=$(stat -f "%Su" "$REPO_REAL" 2>/dev/null || echo "dtoro")