See node preparation and recovery for host setup. Intel GPU shares are scheduling slots, not additional physical GPUs.
⌘I
{"docsConfig":{"theme":"almond","$schema":"https://mintlify.com/docs.json","name":"Augustin's Homelab","colors":{"primary":"#0066FF","light":"#9BFFFF","dark":"#0055D5"},"seo":{"indexing":"all"},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"augustin","hasAudioNarration":false,"actualSubdomain":"augustin","customDomains":["docs.augustin.ai"],"gitSource":{"type":"github","owner":"amarcin","repo":"homelab","deployBranch":"main","contentDirectory":"docs","isPrivate":true,"mountPath":"","label":""},"entitlements":{},"buildId":"6af106c2277c4b0f6b6a24c0","clientVersion":"0.0.4102","searchFilterCounts":[{"language":"default","tag":"Docs","count":13},{"language":"default","tag":"Operations","count":6},{"language":"default","tag":"Homelab","count":6},{"language":"default","tag":"Blog","count":1},{"language":"default","tag":"Miscellaneous","count":1},{"language":"default","tag":"About","count":1}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":true},"customCss":[{"filePath":"homelab-infra.css","content":".hi-root{--hi-bg:light-dark(#ffffff,#09090b);--hi-ink:light-dark(#27272a,#e4e4e7);--hi-sub:light-dark(#626269,#a1a1aa);--hi-line:light-dark(#d9dddd,#363c40);--hi-edge:light-dark(#aebfbe,#617678);--hi-soft:light-dark(#f2f5f5,#20282b);--hi-accent:light-dark(#0066ff,#91beff);--hi-wash:light-dark(#edf4ff,#1b2c43);--hi-danger:light-dark(#a53331,#f8aaa5);--hi-case:light-dark(#323a3c,#7f8b8e);--hi-metal:light-dark(#b1babd,#98a6aa);--hi-screen:light-dark(#283537,#223135);color:var(--hi-ink);color-scheme:light;font-size:14px;line-height:1.5}.dark .hi-root{color-scheme:dark}.hi-root *{box-sizing:border-box}.hi-root button{font:inherit;color:inherit;cursor:pointer}.hi-root a{color:var(--hi-accent);text-decoration:none}.hi-root a:hover{text-decoration:underline}.hi-root h2,.hi-root p{margin:0}.hi-root h2{font-size:16px;font-weight:500;margin-bottom:6px}.hi-root p{font-size:13px;color:var(--hi-sub)}.hi-links{display:flex;flex-wrap:wrap;gap:8px 16px;font-size:12px;margin-top:12px}.hi-note,.hi-observed{color:var(--hi-sub);font-size:11px;margin-top:20px}.hi-observed{border-top:1px solid var(--hi-line);padding-top:13px}.hi-graph{position:relative;width:100%;isolation:isolate;min-width:0}.hi-edges{position:absolute;inset:0;overflow:visible;z-index:-1;pointer-events:none}.hi-edges path{stroke:var(--hi-edge);stroke-width:1.4;fill:none}.hi-edges path.hi-configured{stroke-dasharray:5 5}.hi-edges path.hi-active{stroke:var(--hi-accent);stroke-width:1.8}.hi-edges path.hi-arrow{stroke:none;fill:var(--hi-edge)}.hi-edges path.hi-arrow-active{stroke:none;fill:var(--hi-accent)}.hi-edges text{font-size:11px;fill:var(--hi-sub);paint-order:stroke;stroke:var(--hi-bg);stroke-width:6px;stroke-linejoin:round}.hi-node{position:absolute;transform:translate(-50%,-50%);padding:6px 5px;border:0;background:var(--hi-bg);border-radius:4px;text-align:center;min-height:66px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:4px}.hi-node strong{font-size:13px;font-weight:500;line-height:1.25}.hi-node small{font-size:11px;color:var(--hi-sub);line-height:1.35}.hi-node[aria-pressed=true]{background:var(--hi-wash)}.hi-fault,.hi-node.hi-fault small{color:var(--hi-danger)}.hi-map-note{position:absolute;font-size:11px;color:var(--hi-sub);max-width:150px;line-height:1.4}.hi-selection{border-top:1px solid var(--hi-line);padding-top:16px;margin-top:18px}.hi-selection p{max-width:680px}.hi-legend{display:flex;align-items:center;gap:9px;margin-top:15px;font-size:11px;color:var(--hi-sub)}.hi-legend:before{content:\"\";width:24px;border-top:1px dashed var(--hi-sub);flex-shrink:0}.hi-machines{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;padding:12px 0 20px}.hi-machines button{border:0;background:transparent;text-align:center;padding:12px 3px;border-radius:5px;min-width:0;display:flex;flex-direction:column;align-items:center}.hi-machines button[aria-pressed=true]{background:var(--hi-soft)}.hi-machines strong{font-size:14px;font-weight:500;margin-top:8px}.hi-machines small{font-size:11px;color:var(--hi-sub);margin-top:3px}.hi-cluster{display:grid;grid-template-columns:3fr 1fr;gap:18px;margin:0 0 24px;text-align:center;color:var(--hi-sub);font-size:11px}.hi-cluster span{border-top:1px solid var(--hi-line);padding-top:8px}.hi-host-detail{border-top:1px solid var(--hi-line);padding-top:22px;display:grid;grid-template-columns:1fr 1fr;gap:28px}.hi-host-detail p{margin-top:12px}.hi-host-detail code{font-size:12px;color:var(--hi-sub)}.hi-host-detail dl{margin:0;display:grid;grid-template-columns:1fr 1fr;gap:16px}.hi-host-detail dt{font-size:11px;color:var(--hi-sub)}.hi-host-detail dd{margin:3px 0 0;font-size:13px;overflow-wrap:anywhere}.hi-host-detail dl>div:last-child{grid-column:1/-1}.hi-groups{display:flex;flex-wrap:wrap;gap:7px 17px;margin-bottom:24px}.hi-groups button{border:0;border-bottom:1px solid transparent;background:transparent;padding:7px 0;font-size:12px;color:var(--hi-sub)}.hi-groups button[aria-pressed=true]{border-bottom-color:var(--hi-accent);color:var(--hi-ink)}.hi-services{display:grid;grid-template-columns:150px minmax(0,1fr);gap:20px;align-items:start}.hi-service-list{display:flex;flex-direction:column}.hi-service-list button{border:0;border-bottom:1px solid var(--hi-line);text-align:left;background:transparent;padding:12px 8px;font-size:13px;min-height:44px}.hi-service-list button[aria-pressed=true]{background:var(--hi-soft)}.hi-service-status{font-size:11px;color:var(--hi-sub);margin-bottom:10px}.hi-service-status.hi-fault{color:var(--hi-danger)}.hi-service-detail{min-width:0}@media (max-width:800px){.hi-services{grid-template-columns:1fr}.hi-service-list{display:grid;grid-template-columns:1fr 1fr}}@media (max-width:580px){.hi-machines{grid-template-columns:1fr 1fr;gap:4px}.hi-cluster{grid-template-columns:1fr;text-align:left}.hi-host-detail{grid-template-columns:1fr;gap:24px}.hi-map-note{max-width:120px}}@media (pointer:coarse){.hi-root button{min-height:44px}}.hi-root .hi-art{height:154px;width:100%;position:relative;display:flex;align-items:flex-end;justify-content:center;padding-bottom:18px;transform:scale(var(--hi-art-scale,1))}.hi-root .hi-tower{width:46px;height:116px;background:var(--hi-case);border-radius:3px;position:relative;box-shadow:7px 5px 0 color-mix(in srgb,var(--hi-case),transparent 55%);transform:skewY(-3deg)}.hi-root .hi-tower:before{content:\"\";position:absolute;left:8px;right:8px;top:48px;bottom:8px;background:repeating-linear-gradient(0deg,transparent 0 3px,color-mix(in srgb,var(--hi-metal),transparent 65%) 3px 4px)}.hi-root .hi-tower:after{content:\"DELL\";position:absolute;top:77px;left:14px;font-size:7px;letter-spacing:1px;color:var(--hi-metal);transform:rotate(-90deg)}.hi-root .hi-tower-slot{position:absolute;width:30px;height:2px;background:var(--hi-metal);top:19px;left:8px;opacity:.65}.hi-root .hi-tower-button{position:absolute;width:7px;height:7px;border-radius:50%;border:1px solid var(--hi-metal);left:9px;top:8px}.hi-root .hi-tower-ports{position:absolute;width:18px;height:4px;top:34px;left:9px;background:repeating-linear-gradient(90deg,var(--hi-metal) 0 5px,transparent 5px 9px)}.hi-root .hi-usb-drive{position:absolute;width:25px;height:43px;background:var(--hi-case);border-radius:7px;left:calc(50% + 24px);bottom:15px;transform:rotate(10deg)}.hi-root .hi-aio{width:116px;height:82px;background:var(--hi-case);border-radius:4px;padding:5px 5px 10px;position:absolute;bottom:48px}.hi-root .hi-screen{height:100%;background:var(--hi-screen)}.hi-root .hi-aio:after{content:\"\";position:absolute;height:22px;width:9px;background:var(--hi-metal);left:calc(50% - 4px);bottom:-21px}.hi-root .hi-aio-foot{position:absolute;bottom:22px;left:calc(50% - 25px);width:50px;height:4px;border-radius:50%;background:var(--hi-metal)}.hi-root .hi-laptop{width:104px;height:72px;background:var(--hi-metal);padding:4px 4px 7px;border-radius:5px 5px 0 0;position:absolute;bottom:32px}.hi-root .hi-laptop-base{height:9px;width:124px;position:absolute;bottom:23px;background:var(--hi-metal);border-radius:0 0 6px 6px;clip-path:polygon(8% 0,92% 0,100% 75%,95% 100%,5% 100%,0 75%)}"}],"page":{"pagePath":"infrastructure/hardware","slug":"/infrastructure/hardware","pageMetadata":{"title":"Hardware","description":"Three k3s nodes and a separate Mac.","href":"/infrastructure/hardware"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Three k3s nodes and a separate Mac.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];const __snippet_DATA_14dwlcs={\"sections\":[[`hardware`,`Hardware`,`computer`],[`services`,`Services`,`layers`],[`agents`,`Agents`,`bot`],[`inference`,`Inference`,`sparkles`],[`network`,`Network`,`network`],[`security`,`Security`,`shield-check`]],\"hosts\":[{\"id\":`pentium`,\"name\":`pentium`,\"role\":`Control plane`,\"model\":`Dell OptiPlex 3020 SFF`,\"shape\":`tower`,\"cpu\":`Pentium G3220, 2 threads`,\"ram\":`8 GB`,\"ip\":`192.168.1.16`,\"pods\":`8 Running pods`,\"disks\":`250 GB HDD; no Longhorn disks`,\"text\":`Runs the k3s control plane, both Cloudflare tunnel replicas and Envoy. The NoSchedule taint keeps ordinary applications on the workers.`,\"links\":[{\"label\":`Model documentation`,\"url\":`https://www.dell.com/support/home/en-au/product-support/product/optiplex-3020-desktop/docs`},{\"label\":`GitHub`,\"url\":`https://github.com/k3s-io/k3s`}]},{\"id\":`i3`,\"name\":`i3`,\"role\":`Storage worker`,\"model\":`Dell OptiPlex 3020 SFF`,\"shape\":`storage`,\"cpu\":`Core i3-4130, 4 threads`,\"ram\":`16 GB`,\"ip\":`192.168.1.100`,\"pods\":`69 Running pods`,\"disks\":`500 GB SSD, 2 × 1 TB external, 2 TB SanDisk`,\"text\":`Runs Jellyfin with Intel QuickSync, Home Assistant and most application pods. Longhorn uses the OS disk and the 2 TB external drive. One older Longhorn disk entry is disabled and NotReady.`,\"links\":[{\"label\":`Model documentation`,\"url\":`https://www.dell.com/support/home/en-au/product-support/product/optiplex-3020-desktop/docs`},{\"label\":`GitHub`,\"url\":`https://github.com/k3s-io/k3s`}]},{\"id\":`i5`,\"name\":`i5`,\"role\":`Compute worker`,\"model\":`Dell Inspiron 5490 AIO`,\"shape\":`aio`,\"cpu\":`Core i5-10210U, 8 threads`,\"ram\":`12 GB`,\"ip\":`192.168.1.10`,\"pods\":`46 Running pods`,\"disks\":`256 GB NVMe, 1 TB HDD`,\"text\":`Runs Frigate, BookOrbit and Shelfmark. The two book applications share a volume and run on the same node. The kiosk deployment is scaled to zero.`,\"links\":[{\"label\":`Model documentation`,\"url\":`https://www.dell.com/support/home/en-au/product-support/product/inspiron-24-5490-aio/docs`},{\"label\":`GitHub`,\"url\":`https://github.com/k3s-io/k3s`}]},{\"id\":`mac`,\"name\":`MacBook Pro`,\"role\":`macOS`,\"model\":`13-inch MacBook Pro M1, 2020`,\"shape\":`laptop`,\"cpu\":`Apple M1, 8 CPU cores`,\"ram\":`16 GB`,\"ip\":`192.168.1.35`,\"pods\":`Outside k3s`,\"disks\":`256 GB internal SSD`,\"text\":`Runs the native Codex app-server, a GitHub Actions runner and the MCP proxy for Messages, Photos and Voice Memos. Symphony is installed but stopped.`,\"links\":[{\"label\":`Model documentation`,\"url\":`https://support.apple.com/en-au/111893`}]}],\"graphs\":{\"network\":{\"height\":650,\"mheight\":1170,\"selected\":`envoy`,\"notes\":[{\"text\":`LAN · 192.168.1.0/24`,\"x\":38,\"y\":96,\"mx\":5,\"my\":37}],\"nodes\":[{\"id\":`browser`,\"name\":`Browser`,\"sub\":`Web / MCP client`,\"ico\":`globe`,\"x\":13,\"y\":7,\"mx\":24,\"my\":4,\"text\":`Web requests and MCP requests enter through Cloudflare. Browser OIDC and machine tokens use different Envoy policies.`,\"fault\":false,\"links\":[]},{\"id\":`cf`,\"name\":`Cloudflare`,\"sub\":`HTTPS edge`,\"ico\":`cloud`,\"x\":45,\"y\":8,\"mx\":73,\"my\":10,\"text\":`Cloudflare accepts HTTPS. The home tunnel establishes outbound connections, so this documented web path does not need an inbound router port forward.`,\"fault\":false,\"links\":[{\"label\":`Tunnel docs`,\"url\":`https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/`}]},{\"id\":`warp`,\"name\":`Mail client + WARP`,\"sub\":`Private /32 route`,\"ico\":`shield`,\"x\":10,\"y\":40,\"mx\":73,\"my\":88,\"text\":`The repository documents WARP routing to 192.168.1.100/32. Cloudflare route settings and native mail delivery were not queried.`,\"fault\":false,\"links\":[{\"label\":`WARP docs`,\"url\":`https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/warp/`}]},{\"id\":`tunnel`,\"name\":`cloudflared`,\"sub\":`pentium · 2 replicas`,\"ico\":`radio-tower`,\"x\":35,\"y\":27,\"mx\":24,\"my\":22,\"text\":`Both tunnel replicas run on pentium. Two processes on one machine share the same host failure risk.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/cloudflare/cloudflared`}]},{\"id\":`envoy`,\"name\":`Envoy`,\"sub\":`pentium · :8890`,\"ico\":`signpost`,\"x\":48,\"y\":45,\"mx\":73,\"my\":35,\"text\":`Envoy listens on the pentium host network at port 8890. Hostname and path select an HTTPRoute, then a Service. The documented tunnel-to-Envoy origin hop uses HTTP.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/envoyproxy/gateway`}]},{\"id\":`i3apps`,\"name\":`i3 applications`,\"sub\":`ClusterIP → pod`,\"ico\":`server`,\"x\":23,\"y\":70,\"mx\":24,\"my\":48,\"text\":`ClusterIP Services forward to selected pods. Jellyfin, Home Assistant, custom agents and many other applications currently run on i3. Internal service traffic does not automatically pass through the public OIDC gate.`,\"fault\":false,\"links\":[]},{\"id\":`i5apps`,\"name\":`i5 applications`,\"sub\":`ClusterIP → pod`,\"ico\":`server`,\"x\":49,\"y\":88,\"mx\":73,\"my\":60,\"text\":`The same gateway reaches Services whose current pods are on i5, including Frigate, BookOrbit and Shelfmark. A workload can move unless scheduling rules pin it.`,\"fault\":false,\"links\":[]},{\"id\":`macsvc`,\"name\":`mac.peripherals`,\"sub\":`Manual EndpointSlice`,\"ico\":`network`,\"x\":80,\"y\":45,\"mx\":24,\"my\":68,\"text\":`This selectorless Kubernetes Service has a manual EndpointSlice for 192.168.1.35:8096. It reaches the separate Mac host, rather than selecting a Kubernetes pod.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/peripherals/mac`}]},{\"id\":`mac`,\"name\":`Mac MCP proxy`,\"sub\":`.35:8096`,\"ico\":`laptop`,\"x\":83,\"y\":70,\"mx\":73,\"my\":76,\"text\":`The proxy binds 0.0.0.0:8096. It starts and routes requests to three named MCP subprocesses on macOS.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/scripts/mac/mcp-proxy`}]},{\"id\":`apple`,\"name\":`Messages · Photos`,\"sub\":`Voice Memos`,\"ico\":`plug`,\"x\":82,\"y\":92,\"mx\":24,\"my\":83,\"text\":`These are the three observed named proxy servers. Contacts and Apple Passwords use separately documented SSH tools.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/scripts/mac/mcp-proxy`}]},{\"id\":`mail`,\"name\":`Stalwart`,\"sub\":`i3 service · native TLS`,\"ico\":`mail`,\"x\":10,\"y\":93,\"mx\":24,\"my\":96,\"text\":`The Service claims i3’s LAN IP for ports 993, 465, 587 and 4190, forwarding to Stalwart. Its HTTP route returned 503. Native mail delivery remains untested.`,\"fault\":false,\"links\":[]}],\"edges\":[{\"from\":`browser`,\"to\":`cf`,\"label\":`HTTPS`,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`cf`,\"to\":`tunnel`,\"label\":``,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`tunnel`,\"to\":`envoy`,\"label\":`HTTP :8890`,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`envoy`,\"to\":`i3apps`,\"label\":``,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`envoy`,\"to\":`i5apps`,\"label\":``,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`envoy`,\"to\":`macsvc`,\"label\":``,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`macsvc`,\"to\":`mac`,\"label\":`:8096`,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`mac`,\"to\":`apple`,\"label\":``,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`warp`,\"to\":`mail`,\"label\":`Native mail`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null}]},\"security\":{\"height\":700,\"mheight\":1260,\"selected\":`pocket`,\"nodes\":[{\"id\":`person`,\"name\":`Browser`,\"sub\":`Passkey sign-in`,\"ico\":`fingerprint`,\"x\":13,\"y\":10,\"mx\":24,\"my\":4,\"text\":`A browser can sign in through an Envoy gate or through the application’s own OIDC integration. Those are separate clients of Pocket ID.`,\"fault\":false,\"links\":[]},{\"id\":`pocket`,\"name\":`Pocket ID`,\"sub\":`Issuer · groups`,\"ico\":`key-round`,\"x\":51,\"y\":20,\"mx\":73,\"my\":17,\"text\":`Pocket ID issues identity and group claims. The configured groups are guest and admins. Each gateway or application still decides what the user may do.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/pocket-id/pocket-id`}]},{\"id\":`gate`,\"name\":`Envoy OIDC gate`,\"sub\":`13 route policies`,\"ico\":`shield-check`,\"x\":23,\"y\":43,\"mx\":24,\"my\":31,\"text\":`Envoy gates selected browser HTTPRoutes, including the media managers, Vaultwarden’s browser, Bifrost and Temporal UI. It does not gate every service or every path.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/envoyproxy/gateway`}]},{\"id\":`gated`,\"name\":`Gated web apps`,\"sub\":`Vaultwarden · Radarr…`,\"ico\":`app-window`,\"x\":13,\"y\":70,\"mx\":24,\"my\":48,\"text\":`The browser gate is one access check. The application may also require its own account. Vaultwarden’s API, identity and notification paths bypass this OIDC gate and use vault authentication.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/infra/envoy-oidc`}]},{\"id\":`native`,\"name\":`Native app OIDC`,\"sub\":`Outline · Grafana…`,\"ico\":`app-window`,\"x\":78,\"y\":43,\"mx\":73,\"my\":40,\"text\":`Grafana, Shelfmark, RomM and Outline have native Pocket ID integration in source. BookOrbit and Jellyfin SSO are documented in application state. A logged-in journey was not tested.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/docs/adding-people.md`}]},{\"id\":`machine`,\"name\":`Machine client`,\"sub\":`Bearer JWT / API key`,\"ico\":`bot`,\"x\":78,\"y\":76,\"mx\":73,\"my\":61,\"text\":`Machine routes use bearer JWT or a separately matched x-api-key route. A browser session is not the machine credential.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/mcp`}]},{\"id\":`jwt`,\"name\":`Envoy MCP policy`,\"sub\":`Issuer + audience`,\"ico\":`shield`,\"x\":51,\"y\":62,\"mx\":24,\"my\":64,\"text\":`The JWT policy checks issuer and audience. Anonymous Messages and Vaultwarden MCP probes returned 401 at the origin. The API-key route excludes Vaultwarden MCP.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/envoyproxy/gateway`}]},{\"id\":`mcp`,\"name\":`MCP servers`,\"sub\":`Mac · vault · mail…`,\"ico\":`plug`,\"x\":40,\"y\":90,\"mx\":24,\"my\":81,\"text\":`The MCP policy protects requests through Envoy. Direct LAN access has different boundaries, including the Mac proxy listening on all interfaces with its firewall disabled.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/mcp`}]},{\"id\":`local`,\"name\":`Application accounts`,\"sub\":`HA · mail · ntfy`,\"ico\":`user-round`,\"x\":85,\"y\":95,\"mx\":73,\"my\":92,\"text\":`Home Assistant, Stalwart and ntfy keep local identities. Seerr uses Jellyfin identity. Application-specific credentials still apply on these paths.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/docs/adding-people.md`}]}],\"edges\":[{\"from\":`person`,\"to\":`gate`,\"label\":``,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`gate`,\"to\":`pocket`,\"label\":`OIDC`,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`native`,\"to\":`pocket`,\"label\":`OIDC`,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`person`,\"to\":`native`,\"label\":`App login`,\"configured\":false,\"bend\":0,\"both\":false,\"via\":[[95,4],[95,43]],\"mvia\":[[98,4],[98,40]]},{\"from\":`gate`,\"to\":`gated`,\"label\":``,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`machine`,\"to\":`jwt`,\"label\":``,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`jwt`,\"to\":`pocket`,\"label\":`JWT issuer`,\"configured\":false,\"bend\":-30,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`jwt`,\"to\":`mcp`,\"label\":``,\"configured\":false,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null}]},\"agents\":{\"height\":810,\"mheight\":1300,\"selected\":`worker`,\"notes\":[{\"text\":`Native Mac Codex`,\"x\":5,\"y\":1,\"mx\":4,\"my\":1},{\"text\":`Cluster agents`,\"x\":3,\"y\":40,\"mx\":4,\"my\":35}],\"nodes\":[{\"id\":`client`,\"name\":`Codex client`,\"sub\":`Personal task`,\"ico\":`message-square`,\"x\":13,\"y\":11,\"mx\":24,\"my\":7,\"text\":`A client submits the task to the native app-server on the Mac. This path has separate execution state from the custom cluster agents.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/openai/codex`}]},{\"id\":`codex`,\"name\":`Mac app-server`,\"sub\":`Running · v0.154.0`,\"ico\":`laptop`,\"x\":43,\"y\":17,\"mx\":73,\"my\":14,\"text\":`The Mac daemon owns the task and its tools. It uses direct Bedrock Runtime inference. It does not pass through Temporal or Bifrost.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/openai/codex`}]},{\"id\":`bedrock`,\"name\":`Bedrock Runtime`,\"sub\":`Remote model`,\"ico\":`cloud`,\"x\":80,\"y\":8,\"mx\":73,\"my\":5,\"text\":`Native Mac Codex uses the amazon-bedrock-runtime provider. No global model name was set in the inspected configuration.`,\"fault\":false,\"links\":[{\"label\":`Bedrock docs`,\"url\":`https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html`}]},{\"id\":`ctools`,\"name\":`Codex tools`,\"sub\":`Shell · configured MCP`,\"ico\":`wrench`,\"x\":79,\"y\":29,\"mx\":24,\"my\":27,\"text\":`The daemon uses its configured shell and MCP capabilities. Available tools are configuration, not evidence of recent personal actions.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/scripts/mac`}]},{\"id\":`request`,\"name\":`Linear / API`,\"sub\":`Task submission`,\"ico\":`webhook`,\"x\":14,\"y\":49,\"mx\":24,\"my\":41,\"text\":`The Linear adapter and agents API submit events and wake the configured custom agent. A separate, older Linear bridge targets OpenCode.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/agent`}]},{\"id\":`api`,\"name\":`agents-api`,\"sub\":`i3 · adapter on i5`,\"ico\":`send`,\"x\":35,\"y\":57,\"mx\":73,\"my\":48,\"text\":`Submission writes to the PostgreSQL event log and starts a Temporal wake. The API and worker currently run on i3; agent-linear runs on i5.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/images/agent`}]},{\"id\":`event`,\"name\":`PostgreSQL`,\"sub\":`Event log + cursor`,\"ico\":`database`,\"x\":20,\"y\":83,\"mx\":24,\"my\":69,\"text\":`The event log is the authoritative record. The worker reads and writes events and advances its cursor. Temporal workflow runs coordinate turns.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/postgres/postgres`}]},{\"id\":`temporal`,\"name\":`Temporal`,\"sub\":`Wake / orchestration`,\"ico\":`workflow`,\"x\":56,\"y\":44,\"mx\":73,\"my\":39,\"text\":`Temporal wakes the custom worker. Its workflow can complete when idle, then resume work after a new event.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/temporalio/temporal`}]},{\"id\":`worker`,\"name\":`Custom worker`,\"sub\":`i3`,\"ico\":`bot`,\"x\":55,\"y\":69,\"mx\":73,\"my\":64,\"text\":`The custom worker consumes events, asks Bifrost for model responses and uses workspaces or MCP tools. These connections are established in code and configuration; no task was executed during collection.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/images/agent`}]},{\"id\":`bifrost`,\"name\":`Bifrost`,\"sub\":`Model requests`,\"ico\":`route`,\"x\":84,\"y\":51,\"mx\":24,\"my\":53,\"text\":`The legacy custom worker and OpenCode use Bifrost. Native Mac Codex uses its own direct Runtime path.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/maximhq/bifrost`}]},{\"id\":`workspace`,\"name\":`Workspace pods`,\"sub\":`None active in snapshot`,\"ico\":`folder-code`,\"x\":85,\"y\":76,\"mx\":73,\"my\":79,\"text\":`The worker can start per-agent workspace pods. None were active at collection. Workspace storage has one replica and no backup.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/images/agent`}]},{\"id\":`tools`,\"name\":`Search / browser MCP`,\"sub\":`SearXNG · Steel`,\"ico\":`plug`,\"x\":60,\"y\":94,\"mx\":24,\"my\":90,\"text\":`Configured tools provide web search and a browser. They are tool services, rather than another agent orchestrator.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/searxng/searxng`}]},{\"id\":`ntfy`,\"name\":`ntfy`,\"sub\":`Escalation / notification`,\"ico\":`bell`,\"x\":86,\"y\":94,\"mx\":73,\"my\":96,\"text\":`The custom worker can request a notification or escalation through ntfy.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/binwiederhier/ntfy`}]},{\"id\":`oldbridge`,\"name\":`Older Linear bridge`,\"sub\":`Separate path`,\"ico\":`webhook`,\"x\":13,\"y\":65,\"mx\":24,\"my\":61,\"text\":`The older bridge targets OpenCode. It is distinct from the custom worker path.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/images/linear-bridge`}]},{\"id\":`opencode`,\"name\":`OpenCode`,\"sub\":`236 restarts · HTTP 503`,\"ico\":`terminal`,\"x\":11,\"y\":96,\"mx\":24,\"my\":99,\"text\":`The OpenCode container was in CrashLoopBackOff. Both its origin and external HTTP route returned 503.`,\"fault\":true,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/anomalyco/opencode`}]}],\"edges\":[{\"from\":`client`,\"to\":`codex`,\"label\":`Task`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`codex`,\"to\":`bedrock`,\"label\":`Inference`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`codex`,\"to\":`ctools`,\"label\":`Tool calls`,\"configured\":true,\"bend\":0,\"both\":true,\"via\":null,\"mvia\":null},{\"from\":`request`,\"to\":`api`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`api`,\"to\":`event`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`api`,\"to\":`temporal`,\"label\":`Wake`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`temporal`,\"to\":`worker`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`worker`,\"to\":`event`,\"label\":`Read / write`,\"configured\":true,\"bend\":0,\"both\":true,\"via\":null,\"mvia\":null},{\"from\":`worker`,\"to\":`bifrost`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`worker`,\"to\":`workspace`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`worker`,\"to\":`tools`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`worker`,\"to\":`ntfy`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`oldbridge`,\"to\":`opencode`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null}]},\"inference\":{\"height\":650,\"mheight\":1110,\"selected\":`bifrost`,\"notes\":[{\"text\":`Direct Runtime`,\"x\":4,\"y\":1,\"mx\":4,\"my\":1},{\"text\":`Bifrost routing`,\"x\":4,\"y\":34,\"mx\":4,\"my\":29}],\"nodes\":[{\"id\":`codex`,\"name\":`Mac Codex`,\"sub\":`Native app-server`,\"ico\":`laptop`,\"x\":16,\"y\":16,\"mx\":24,\"my\":9,\"text\":`The Mac selects the Bedrock Runtime provider directly. There is no inspected global model setting and no local inference server in this path.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/openai/codex`}]},{\"id\":`runtime`,\"name\":`Bedrock Runtime`,\"sub\":`Remote inference`,\"ico\":`cloud`,\"x\":77,\"y\":14,\"mx\":73,\"my\":19,\"text\":`The Mac invokes the remote Runtime service using its short-lived AWS profile. Current documentation ties profile renewal to the work laptop.`,\"fault\":false,\"links\":[{\"label\":`Bedrock docs`,\"url\":`https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html`}]},{\"id\":`agent`,\"name\":`Custom agent`,\"sub\":`i3`,\"ico\":`bot`,\"x\":14,\"y\":48,\"mx\":24,\"my\":37,\"text\":`The custom worker’s configured model requests use Bifrost’s Anthropic-compatible interface. Opus and the Sonnet judge are configured labels, not tested availability.`,\"fault\":false,\"links\":[]},{\"id\":`oc`,\"name\":`OpenCode`,\"sub\":`Currently unavailable`,\"ico\":`terminal`,\"x\":17,\"y\":76,\"mx\":24,\"my\":57,\"text\":`OpenCode has configured Cecelia and Kiro choices, but the observed container is crash-looping.`,\"fault\":true,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/anomalyco/opencode`}]},{\"id\":`bifrost`,\"name\":`Bifrost 1.6.7`,\"sub\":`/anthropic · i3`,\"ico\":`route`,\"x\":46,\"y\":59,\"mx\":73,\"my\":47,\"text\":`Bifrost routes legacy agent requests. Git supplies file configuration and SQLite holds runtime state. A healthy gateway does not establish that credentials or a model call work.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/maximhq/bifrost`}]},{\"id\":`cecelia`,\"name\":`Cecelia`,\"sub\":`Bedrock · us-west-2`,\"ico\":`cloud`,\"x\":82,\"y\":43,\"mx\":73,\"my\":71,\"text\":`The Cecelia branch uses Bedrock with refreshed runtime STS state and an Anthropic model catalogue.`,\"fault\":false,\"links\":[{\"label\":`Bedrock docs`,\"url\":`https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html`}]},{\"id\":`adapter`,\"name\":`AIClient2API`,\"sub\":`/claude-kiro-oauth`,\"ico\":`shuffle`,\"x\":71,\"y\":80,\"mx\":24,\"my\":83,\"text\":`The Kiro branch reaches the AIClient2API adapter before the upstream Kiro service.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/justlovemaki/AIClient2API`}]},{\"id\":`kiro`,\"name\":`Kiro`,\"sub\":`Remote upstream`,\"ico\":`cloud`,\"x\":86,\"y\":96,\"mx\":73,\"my\":96,\"text\":`This is a separate configured upstream. No model request was sent during the investigation.`,\"fault\":false,\"links\":[]}],\"edges\":[{\"from\":`codex`,\"to\":`runtime`,\"label\":`AWS profile`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`agent`,\"to\":`bifrost`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`oc`,\"to\":`bifrost`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`bifrost`,\"to\":`cecelia`,\"label\":`STS`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`bifrost`,\"to\":`adapter`,\"label\":`Kiro route`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`adapter`,\"to\":`kiro`,\"label\":``,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null}]}},\"services\":[{\"id\":`jellyfin`,\"name\":`Jellyfin`,\"group\":`Media`,\"ico\":`clapperboard`,\"text\":`Streams the shared film and television library. Intel QuickSync on i3 transcodes video when a client needs another format.`,\"node\":`i3`,\"status\":`Pod ready; Jellyfin SSO documented`,\"deps\":[`Shared library`,`Intel QuickSync`,`Pocket ID`],\"links\":[{\"label\":`Open`,\"url\":`https://jellyfin.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/jellyfin/jellyfin`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/media/jellyfin`}]},{\"id\":`seerr`,\"name\":`Seerr`,\"group\":`Media`,\"ico\":`ticket`,\"text\":`Sends television requests to Sonarr and film requests to Radarr. Accounts follow Jellyfin identity.`,\"node\":`i5`,\"status\":`Pod ready; login page reached`,\"deps\":[`Jellyfin`,`Sonarr`,`Radarr`],\"links\":[{\"label\":`Open`,\"url\":`https://seerr.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/seerr-team/seerr`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/media/seerr`}]},{\"id\":`shelfmark`,\"name\":`Shelfmark`,\"group\":`Media`,\"ico\":`bookmark-plus`,\"text\":`Searches and downloads books into BookOrbit’s Book Dock. Both applications share a volume and run on i5. External requests can use the Gluetun proxy.`,\"node\":`i5`,\"status\":`Pod ready; native OIDC configured`,\"deps\":[`BookOrbit`,`Prowlarr`,`qBittorrent`,`Gluetun`],\"links\":[{\"label\":`Open`,\"url\":`https://shelfmark.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/calibrain/shelfmark`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/media/shelfmark`}]},{\"id\":`bookorbit`,\"name\":`BookOrbit`,\"group\":`Media`,\"ico\":`book-open`,\"text\":`Reads and plays the book library. Shelfmark delivers files through a shared Book Dock volume. PostgreSQL stores application data.`,\"node\":`i5`,\"status\":`Pod ready; web root reached`,\"deps\":[`Shelfmark`,`Book Dock volume`,`PostgreSQL`],\"links\":[{\"label\":`Open`,\"url\":`https://bookorbit.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/bookorbit/bookorbit`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/media/bookorbit`}]},{\"id\":`romm`,\"name\":`RomM`,\"group\":`Games`,\"ico\":`gamepad-2`,\"text\":`Stores a retro game collection and its metadata. Pocket ID handles sign-in, and a dedicated PostgreSQL cluster stores application data.`,\"node\":`i3`,\"status\":`Pod ready; web root reached`,\"deps\":[`Pocket ID`,`PostgreSQL`,`Game library`],\"links\":[{\"label\":`Open`,\"url\":`https://romm.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/rommapp/romm`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/games/romm`}]},{\"id\":`luanti`,\"name\":`Luanti`,\"group\":`Games`,\"ico\":`blocks`,\"text\":`Hosts a voxel game world. Players use a UDP service rather than the HTTP gateway.`,\"node\":`i3`,\"status\":`Pod ready; gameplay untested`,\"deps\":[`UDP service`,`World volume`],\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/luanti-org/luanti`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/games/luanti`}]},{\"id\":`outline`,\"name\":`Outline`,\"group\":`Knowledge`,\"ico\":`notebook-pen`,\"text\":`Stores documents and notes with PostgreSQL and Redis. The application uses Pocket ID directly for sign-in.`,\"node\":`i3`,\"status\":`Pod ready; web root reached`,\"deps\":[`Pocket ID`,`PostgreSQL`,`Redis`],\"links\":[{\"label\":`Open`,\"url\":`https://outline.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/outline/outline`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/apps/outline`}]},{\"id\":`excalideck`,\"name\":`Excalideck`,\"group\":`Knowledge`,\"ico\":`pen-tool`,\"text\":`Edits diagrams. A separate collaboration service handles shared sessions. The browser HTTPRoute has an Envoy OIDC gate.`,\"node\":`i5`,\"status\":`Pods ready; browser sign-in required`,\"deps\":[`Pocket ID gate`,`Collaboration service`],\"links\":[{\"label\":`Open`,\"url\":`https://excalideck.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/amarcin/excalideck`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/apps/excalideck`}]},{\"id\":`miniflux`,\"name\":`Miniflux`,\"group\":`Personal`,\"ico\":`rss`,\"text\":`Collects RSS feeds in PostgreSQL. RSSHub and the feed scraper supply sources; Nextflux is an alternative reading interface.`,\"node\":`i3`,\"status\":`Pod ready; login page reached`,\"deps\":[`PostgreSQL`,`RSSHub`,`Feed scraper`,`Nextflux`],\"links\":[{\"label\":`Open`,\"url\":`https://miniflux.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/miniflux/v2`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/reader/miniflux`}]},{\"id\":`sure`,\"name\":`Sure`,\"group\":`Personal`,\"ico\":`wallet`,\"text\":`Tracks personal finances. PostgreSQL stores records, Redis supports the worker, and a scheduled job performs sync.`,\"node\":`i5`,\"status\":`Pod ready; app sign-in required`,\"deps\":[`PostgreSQL`,`Redis`,`Sync worker`],\"links\":[{\"label\":`Open`,\"url\":`https://sure.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/we-promise/sure`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/apps/sure`}]},{\"id\":`trips`,\"name\":`Trips`,\"group\":`Personal`,\"ico\":`map`,\"text\":`Shows travel plans supplied by an upcoming-trip API and a scheduled sync.`,\"node\":`i3`,\"status\":`Pod ready; web root reached`,\"deps\":[`Upcoming-trip API`,`Scheduled sync`],\"links\":[{\"label\":`Open`,\"url\":`https://trips.augustin.ai`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/apps/trips`}]},{\"id\":`yamtrack`,\"name\":`Yamtrack`,\"group\":`Personal`,\"ico\":`list-checks`,\"text\":`Tracks watched and read media. Redis supports background tasks.`,\"node\":`i3`,\"status\":`Pod ready; app sign-in required`,\"deps\":[`Redis`,`Application accounts`],\"links\":[{\"label\":`Open`,\"url\":`https://yamtrack.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/FuzzyGrim/Yamtrack`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/apps/yamtrack`}]},{\"id\":`vaultwarden`,\"name\":`Vaultwarden`,\"group\":`Personal`,\"ico\":`key-round`,\"text\":`Stores a Bitwarden-compatible password vault. The browser has an Envoy OIDC gate. Native clients and API paths use vault authentication.`,\"node\":`i3`,\"status\":`Pod ready; browser gate reached`,\"deps\":[`Pocket ID gate`,`Vault storage`,`Vault MCP`],\"links\":[{\"label\":`Open`,\"url\":`https://vaultwarden.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/dani-garcia/vaultwarden`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/apps/vaultwarden`}]},{\"id\":`ha`,\"name\":`Home Assistant`,\"group\":`Home`,\"ico\":`house`,\"text\":`Controls home devices on i3. Mosquitto carries device messages. Home Assistant keeps its own user accounts.`,\"node\":`i3`,\"status\":`Pod ready; device actions untested`,\"deps\":[`Mosquitto`,`Host devices`],\"links\":[{\"label\":`Open`,\"url\":`https://home-assistant.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/home-assistant/core`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/peripherals/home-assistant`}]},{\"id\":`frigate`,\"name\":`Frigate`,\"group\":`Home`,\"ico\":`cctv`,\"text\":`Processes camera streams on i5. go2rtc on i3 supplies streams, and Intel graphics support video processing.`,\"node\":`i5`,\"status\":`Pod ready; camera feeds unopened`,\"deps\":[`go2rtc`,`Intel graphics`,`Recording volume`],\"links\":[{\"label\":`Open`,\"url\":`https://frigate.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/blakeblackshear/frigate`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/peripherals/frigate`}]},{\"id\":`stalwart`,\"name\":`Stalwart`,\"group\":`Home`,\"ico\":`mail`,\"text\":`Hosts mail for Bulwark and native clients. Native mail uses the documented WARP route. The web route returned 503, while the pod and endpoint were ready.`,\"node\":`i3`,\"status\":`HTTP 503; native mail untested`,\"deps\":[`Bulwark`,`WARP mail service`,`Stalwart MCP`],\"links\":[{\"label\":`Open`,\"url\":`https://stalwart.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/stalwartlabs/stalwart`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/mail/stalwart`}]},{\"id\":`codex`,\"name\":`Mac Codex`,\"group\":`AI`,\"ico\":`bot`,\"text\":`Runs personal coding tasks in the native Mac app-server. Model requests go directly to Bedrock Runtime.`,\"node\":`Mac`,\"status\":`Daemon running, v0.154.0`,\"deps\":[`Bedrock Runtime`,`Shell / MCP tools`],\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/openai/codex`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/scripts/mac`}]},{\"id\":`custom`,\"name\":`Custom agents`,\"group\":`AI`,\"ico\":`workflow`,\"text\":`Writes task events to PostgreSQL and uses Temporal to wake a custom worker. The worker can create workspaces and call model and tool services.`,\"node\":`i3 / i5`,\"status\":`Deployments ready; task untested`,\"deps\":[`Temporal`,`PostgreSQL event log`,`Bifrost`,`Search / browser MCP`],\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/agent`}]},{\"id\":`opencode`,\"name\":`OpenCode`,\"group\":`AI`,\"ico\":`terminal`,\"text\":`The older coding service is unavailable. Its container had 236 restarts and both HTTP routes returned 503.`,\"node\":`i5`,\"status\":`CrashLoopBackOff; HTTP 503`,\"deps\":[`Bifrost`,`Project volume`,`Older Linear bridge`],\"links\":[{\"label\":`Open`,\"url\":`https://opencode.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/anomalyco/opencode`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/agent/opencode`}]},{\"id\":`bifrost`,\"name\":`Bifrost`,\"group\":`AI`,\"ico\":`route`,\"text\":`Routes legacy model requests to Cecelia’s Bedrock branch or to Kiro through AIClient2API. Git configuration and runtime SQLite state are separate.`,\"node\":`i3`,\"status\":`Pod ready; inference untested`,\"deps\":[`Cecelia / Bedrock`,`AIClient2API / Kiro`,`Runtime SQLite`],\"links\":[{\"label\":`Open`,\"url\":`https://bifrost.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/maximhq/bifrost`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/infra/bifrost`}]},{\"id\":`pocketid`,\"name\":`Pocket ID`,\"group\":`Platform`,\"ico\":`fingerprint`,\"text\":`Issues OIDC identity and guest/admins group claims. Selected Envoy routes and native apps use separate OIDC clients.`,\"node\":`i3`,\"status\":`Pod ready; origin discovery checked`,\"deps\":[`Passkeys`,`OIDC clients`,`Group claims`],\"links\":[{\"label\":`Open`,\"url\":`https://pocket-id.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/pocket-id/pocket-id`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/infra/pocket-id`}]},{\"id\":`longhorn`,\"name\":`Longhorn`,\"group\":`Platform`,\"ico\":`hard-drive`,\"text\":`Replicates application volumes on i3 and i5. Platform volumes normally have two replicas; bulk volumes have one. The shared media volume had no recorded backup.`,\"node\":`i3 / i5`,\"status\":`Attached volumes healthy at collection`,\"deps\":[`i3 disks`,`i5 disks`,`Selected S3 backups`],\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/longhorn/longhorn`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/infra/longhorn`}]},{\"id\":`monitoring`,\"name\":`Grafana \u0026 Beszel`,\"group\":`Platform`,\"ico\":`activity`,\"text\":`Beszel collects host metrics. Alloy sends pod logs to Loki for Grafana.`,\"node\":`Linux nodes`,\"status\":`Pods ready; signed-in views untested`,\"deps\":[`Beszel agents`,`Alloy`,`Loki`],\"links\":[{\"label\":`Open`,\"url\":`https://grafana.augustin.ai`},{\"label\":`GitHub`,\"url\":`https://github.com/grafana/grafana`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/infra/monitoring`},{\"label\":`Beszel GitHub`,\"url\":`https://github.com/henrygd/beszel`}]},{\"id\":`flux`,\"name\":`Flux`,\"group\":`Platform`,\"ico\":`git-branch`,\"text\":`Reconciles the Kubernetes configuration from Git. All three Kustomizations reported Ready at the same Git revision.`,\"node\":`i3 / i5`,\"status\":`3 reconciliations Ready`,\"deps\":[`Git repository`,`Kubernetes API`,`BuildKit / GHCR`],\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/fluxcd/flux2`},{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/flux-system`}]}],\"mediaGraph\":{\"label\":`Media dependencies`,\"height\":590,\"mheight\":970,\"selected\":`jellyfin`,\"nodes\":[{\"id\":`seerr`,\"name\":`Seerr`,\"sub\":`Requests`,\"ico\":`ticket`,\"x\":14,\"y\":10,\"mx\":24,\"my\":6,\"text\":`Seerr sends television requests to Sonarr and film requests to Radarr.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/seerr-team/seerr`}]},{\"id\":`sonarr`,\"name\":`Sonarr / Radarr`,\"sub\":`Series / films`,\"ico\":`film`,\"x\":41,\"y\":25,\"mx\":73,\"my\":19,\"text\":`Sonarr and Radarr choose releases, send downloads to qBittorrent and import finished files into the shared library.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/Sonarr/Sonarr`}]},{\"id\":`prowlarr`,\"name\":`Prowlarr`,\"sub\":`Search indexers`,\"ico\":`search`,\"x\":84,\"y\":9,\"mx\":73,\"my\":5,\"text\":`Prowlarr supplies indexer search results to the media managers.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/Prowlarr/Prowlarr`}]},{\"id\":`download`,\"name\":`qBittorrent`,\"sub\":`Gluetun VPN pod`,\"ico\":`download`,\"x\":76,\"y\":49,\"mx\":73,\"my\":43,\"text\":`qBittorrent shares the downloads pod with Gluetun, qsticky and FlareSolverr on i3. Download traffic uses the VPN.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/qbittorrent/qBittorrent`}]},{\"id\":`library`,\"name\":`Shared library`,\"sub\":`Longhorn bulk · 1 replica`,\"ico\":`hard-drive`,\"x\":37,\"y\":70,\"mx\":24,\"my\":65,\"text\":`The shared media volume is 1300 Gi and has one replica. It had no recorded backup at collection.`,\"fault\":false,\"links\":[{\"label\":`Configuration`,\"url\":`https://github.com/amarcin/homelab/tree/main/cluster/apps/media`}]},{\"id\":`jellyfin`,\"name\":`Jellyfin`,\"sub\":`i3 · QuickSync`,\"ico\":`clapperboard`,\"x\":20,\"y\":94,\"mx\":24,\"my\":92,\"text\":`Jellyfin reads the library and serves video. Its Intel GPU can transcode when clients cannot play the stored format.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/jellyfin/jellyfin`}]},{\"id\":`bazarr`,\"name\":`Bazarr`,\"sub\":`Subtitles`,\"ico\":`captions`,\"x\":80,\"y\":86,\"mx\":73,\"my\":80,\"text\":`Bazarr manages subtitles for Sonarr and Radarr media.`,\"fault\":false,\"links\":[{\"label\":`GitHub`,\"url\":`https://github.com/morpheus65535/bazarr`}]}],\"edges\":[{\"from\":`seerr`,\"to\":`sonarr`,\"label\":`Requests`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`sonarr`,\"to\":`prowlarr`,\"label\":`Search`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`sonarr`,\"to\":`download`,\"label\":`Download`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`download`,\"to\":`library`,\"label\":`Files`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`sonarr`,\"to\":`library`,\"label\":`Import`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`library`,\"to\":`jellyfin`,\"label\":`Playback`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null},{\"from\":`bazarr`,\"to\":`library`,\"label\":`Subtitles`,\"configured\":true,\"bend\":0,\"both\":false,\"via\":null,\"mvia\":null}]},\"observedAt\":`2026-11-03T17:15:14Z`,\"sourceRevision\":`47f51580e556c1559a35b147a559f7a5c3ab2b68`,\"projectLinks\":{\"pocket\":`pocket-id/pocket-id`,\"gate\":`envoyproxy/gateway`,\"jwt\":`envoyproxy/gateway`,\"envoy\":`envoyproxy/gateway`,\"tunnel\":`cloudflare/cloudflared`,\"codex\":`openai/codex`,\"client\":`openai/codex`,\"oc\":`anomalyco/opencode`,\"opencode\":`anomalyco/opencode`,\"bifrost\":`maximhq/bifrost`,\"event\":`postgres/postgres`,\"temporal\":`temporalio/temporal`,\"tools\":`searxng/searxng`,\"ntfy\":`binwiederhier/ntfy`,\"prowlarr\":`Prowlarr/Prowlarr`,\"download\":`qbittorrent/qBittorrent`,\"sonarr\":`Sonarr/Sonarr`,\"bazarr\":`morpheus65535/bazarr`,\"jellyfin\":`jellyfin/jellyfin`,\"seerr\":`seerr-team/seerr`,\"adapter\":`justlovemaki/AIClient2API`}};function __snippet_placeNode_14dwlcs(node,width,height,nodeWidth,nodeHeight,compact){const clamp=(value,size,total)=>Math.max(size/2+4,Math.min(total-size/2-4,value));return{x:clamp((compact?node.mx:node.x)*width/100,nodeWidth,width),y:clamp((compact?node.my:node.y)*height/100,nodeHeight,height)}}function __snippet_routeEdge_14dwlcs(edge,a,b,width,height,compact){const anchor=(r,x,y)=>{const dx=x-r.cx,dy=y-r.cy,f=1/Math.max(Math.abs(dx)/(r.w/2+4),Math.abs(dy)/(r.h/2+4));return{x:r.cx+dx*f,y:r.cy+dy*f}};const via=(compact?edge.mvia:edge.via)?.map(([x,y])=>({x:x*width/100,y:y*height/100}));const first=via?.[0],last=via?.at(-1);const p1=anchor(a,first?.x??b.cx,first?.y??b.cy),p2=anchor(b,last?.x??a.cx,last?.y??a.cy);const dx=p2.x-p1.x,dy=p2.y-p1.y,bend=compact?edge.bend?Math.sign(edge.bend)*18:0:edge.bend;let c1,c2;if(Math.abs(dy)>Math.abs(dx)*.65){c1={x:p1.x+bend,y:p1.y+dy*.38};c2={x:p2.x+bend,y:p2.y-dy*.38}}else{c1={x:p1.x+dx*.4,y:p1.y+bend};c2={x:p2.x-dx*.4,y:p2.y+bend}}let d=`M ${p1.x} ${p1.y} C ${c1.x} ${c1.y},${c2.x} ${c2.y},${p2.x} ${p2.y}`;if(via){d=`M ${p1.x} ${p1.y}`;let prev=p1;for(const next of[...via,p2]){const mid=(prev.x+next.x)/2;d+=` C ${mid} ${prev.y},${mid} ${next.y},${next.x} ${next.y}`;prev=next}}return{d,x:Math.max(45,Math.min(width-45,via?(first.x+last.x)/2:(p1.x+3*c1.x+3*c2.x+p2.x)/8)),y:(via?(first.y+last.y)/2:(p1.y+3*c1.y+3*c2.y+p2.y)/8)-6}}const __snippet_Links_14dwlcs=({links=[]})=>{const _components={a:`a`,..._provideComponents()};return _jsx(`div`,{className:`hi-links`,children:links.map(link=>_jsx(_components.a,{href:link.url,target:`_blank`,rel:`noopener noreferrer`,children:link.label},link.url))})};const __snippet_MachineArt_14dwlcs=({host})=>_jsx(`div`,{className:`hi-art`,role:`img`,\"aria-label\":host.model+` illustration`,children:[`tower`,`storage`].includes(host.shape)?_jsxs(_Fragment,{children:[_jsxs(`div`,{className:`hi-tower`,children:[_jsx(`span`,{className:`hi-tower-button`}),_jsx(`span`,{className:`hi-tower-slot`}),_jsx(`span`,{className:`hi-tower-ports`})]}),host.shape===`storage`\u0026\u0026_jsx(`div`,{className:`hi-usb-drive`})]}):host.shape===`aio`?_jsxs(_Fragment,{children:[_jsx(`div`,{className:`hi-aio`,children:_jsx(`div`,{className:`hi-screen`})}),_jsx(`div`,{className:`hi-aio-foot`})]}):_jsxs(_Fragment,{children:[_jsx(`div`,{className:`hi-laptop`,children:_jsx(`div`,{className:`hi-screen`})}),_jsx(`div`,{className:`hi-laptop-base`})]})});const __snippet_Hardware_14dwlcs=()=>{const[selected,setSelected]=useState(`i3`);const host=__snippet_DATA_14dwlcs.hosts.find(x=>x.id===selected);return _jsxs(_Fragment,{children:[_jsx(`div`,{className:`hi-machines`,children:__snippet_DATA_14dwlcs.hosts.map(h=>_jsxs(`button`,{type:`button`,onClick:()=>setSelected(h.id),\"aria-pressed\":selected===h.id,children:[_jsx(__snippet_MachineArt_14dwlcs,{host:h}),_jsx(`strong`,{children:h.name}),_jsx(`small`,{children:h.role})]},h.id))}),_jsxs(`div`,{className:`hi-cluster`,children:[_jsx(`span`,{children:`k3s · pentium, i3, i5`}),_jsx(`span`,{children:`Separate Mac host`})]}),_jsxs(`div`,{className:`hi-host-detail`,\"aria-live\":`polite`,children:[_jsxs(`div`,{children:[_jsx(`h2`,{children:host.model}),_jsx(`code`,{children:host.ip}),_jsx(`p`,{children:host.text}),_jsx(__snippet_Links_14dwlcs,{links:host.links})]}),_jsxs(`dl`,{children:[_jsxs(`div`,{children:[_jsx(`dt`,{children:`Processor`}),_jsx(`dd`,{children:host.cpu})]}),_jsxs(`div`,{children:[_jsx(`dt`,{children:`Memory`}),_jsx(`dd`,{children:host.ram})]}),_jsxs(`div`,{children:[_jsx(`dt`,{children:`System`}),_jsx(`dd`,{children:host.id===`mac`?`macOS 26.6.1`:`Debian 13 · k3s 1.36.2`})]}),_jsxs(`div`,{children:[_jsx(`dt`,{children:`Pods`}),_jsx(`dd`,{children:host.pods})]}),_jsxs(`div`,{children:[_jsx(`dt`,{children:`Storage`}),_jsx(`dd`,{children:host.disks})]})]})]}),_jsx(`small`,{className:`hi-note`,children:`Model illustrations.`})]})};const __snippet_Graph_14dwlcs=({graph,id})=>{const[selected,setSelected]=useState(graph.selected||graph.nodes[0].id);const[width,setWidth]=useState(736),[rects,setRects]=useState({});const container=useRef(null);const compact=width\u003c460,height=compact?graph.mheight:graph.height;const nodeWidth=compact?Math.min(116,(width-18)/2):Math.min(126,width*.2);useEffect(()=>{setSelected(graph.selected||graph.nodes[0].id)},[id]);useEffect(()=>{const el=container.current;if(!el)return;const resize=new ResizeObserver(()=>setWidth(el.clientWidth));resize.observe(el);setWidth(el.clientWidth);return()=>resize.disconnect()},[]);useEffect(()=>{const el=container.current;if(!el)return;const frame=requestAnimationFrame(()=>{const next={};for(const node of el.querySelectorAll(`[data-infra-node]`)){const r=node.getBoundingClientRect(),n=graph.nodes.find(n=>n.id===node.dataset.infraNode),p=__snippet_placeNode_14dwlcs(n,width,height,r.width,r.height,compact);next[n.id]={x:p.x-r.width/2,y:p.y-r.height/2,w:r.width,h:r.height,cx:p.x,cy:p.y}}setRects(next)});return()=>cancelAnimationFrame(frame)},[width,height,id]);const node=graph.nodes.find(n=>n.id===selected)||graph.nodes[0];return _jsxs(_Fragment,{children:[_jsxs(`div`,{ref:container,className:`hi-graph`,style:{height},role:`group`,\"aria-label\":id+` connections`,children:[_jsxs(`svg`,{className:`hi-edges`,width,height,viewBox:`0 0 `+width+` `+height,role:`img`,\"aria-label\":graph.edges.map(e=>e.from+` to `+e.to).join(`; `),children:[_jsx(`defs`,{children:[`off`,`on`].map(state=>_jsx(`marker`,{id:id+`-`+state,viewBox:`0 0 10 10`,refX:`9`,refY:`5`,markerWidth:`5`,markerHeight:`5`,orient:`auto-start-reverse`,children:_jsx(`path`,{className:`hi-arrow `+(state===`on`?`hi-arrow-active`:``),d:`M 1 1 L 9 5 L 1 9 Z`})},state))}),graph.edges.map((edge,i)=>{const a=rects[edge.from],b=rects[edge.to];if(!a||!b)return null;const route=__snippet_routeEdge_14dwlcs(edge,a,b,width,height,compact),active=edge.from===selected||edge.to===selected;return _jsxs(`g`,{children:[_jsx(`path`,{className:(edge.configured?`hi-configured `:``)+(active?`hi-active`:``),d:route.d,markerEnd:`url(#`+id+(active?`-on`:`-off`)+`)`,markerStart:edge.both?`url(#`+id+(active?`-on`:`-off`)+`)`:undefined}),edge.label\u0026\u0026(!compact||active)\u0026\u0026_jsx(`text`,{x:route.x,y:route.y,textAnchor:`middle`,children:edge.label})]},i)})]}),graph.nodes.map(n=>_jsxs(`button`,{type:`button`,className:`hi-node `+(n.fault?`hi-fault`:``),\"data-infra-node\":n.id,onClick:()=>setSelected(n.id),\"aria-pressed\":n.id===selected,style:{left:__snippet_placeNode_14dwlcs(n,width,height,nodeWidth,rects[n.id]?.h||66,compact).x,top:__snippet_placeNode_14dwlcs(n,width,height,nodeWidth,rects[n.id]?.h||66,compact).y,width:nodeWidth},children:[_jsx(`strong`,{children:n.name}),n.sub\u0026\u0026_jsx(`small`,{children:n.sub})]},n.id)),(graph.notes||[]).map((note,i)=>_jsx(`span`,{className:`hi-map-note`,style:{left:(compact?note.mx:note.x)+`%`,top:(compact?note.my:note.y)+`%`},children:note.text},i))]}),_jsxs(`div`,{className:`hi-selection`,\"aria-live\":`polite`,children:[_jsx(`h2`,{children:node.name}),_jsx(`p`,{children:node.text}),_jsx(__snippet_Links_14dwlcs,{links:node.links})]}),graph.edges.some(e=>e.configured)\u0026\u0026_jsx(`div`,{className:`hi-legend`,children:`Dashed connections are documented or configured, not exercised.`})]})};const __snippet_dependencyGraph_14dwlcs=service=>{if([`jellyfin`,`seerr`].includes(service.id))return{...__snippet_DATA_14dwlcs.mediaGraph,selected:service.id,nodes:__snippet_DATA_14dwlcs.mediaGraph.nodes.map(n=>n.id===service.id?{...n,text:service.text,links:service.links}:n)};const deps=service.deps;return{label:service.name+` dependencies`,selected:service.id,height:440,mheight:Math.max(470,deps.length*150),nodes:[{id:service.id,name:service.name,sub:service.node,x:42,y:44,mx:24,my:43,text:service.text,links:service.links},...deps.map((name,i)=>({id:`dep`+i,name,sub:``,x:i%2?83:13,y:i\u003c2?15:84,mx:73,my:8+i*(83/Math.max(1,deps.length-1)),text:service.name+` uses `+name+`. `+service.status+`.`}))],edges:deps.map((_,i)=>({from:service.id,to:`dep`+i,label:``,configured:true,bend:0,both:false}))}};const __snippet_Services_14dwlcs=()=>{const[group,setGroup]=useState(`Media`),[selected,setSelected]=useState(`jellyfin`);const groups=[...new Set(__snippet_DATA_14dwlcs.services.map(s=>s.group))],list=__snippet_DATA_14dwlcs.services.filter(s=>s.group===group),service=list.find(s=>s.id===selected)||list[0];return _jsxs(_Fragment,{children:[_jsx(`div`,{className:`hi-groups`,children:groups.map(name=>_jsx(`button`,{type:`button`,\"aria-pressed\":group===name,onClick:()=>{setGroup(name);setSelected(__snippet_DATA_14dwlcs.services.find(s=>s.group===name).id)},children:name},name))}),_jsxs(`div`,{className:`hi-services`,children:[_jsx(`div`,{className:`hi-service-list`,children:list.map(s=>_jsx(`button`,{type:`button`,onClick:()=>setSelected(s.id),\"aria-pressed\":service.id===s.id,children:s.name},s.id))}),_jsxs(`div`,{className:`hi-service-detail`,children:[_jsx(`div`,{className:`hi-service-status `+([`opencode`,`stalwart`].includes(service.id)?`hi-fault`:``),children:service.node+` · `+service.status}),_jsx(__snippet_Graph_14dwlcs,{graph:__snippet_dependencyGraph_14dwlcs(service),id:`service-`+service.id},service.id)]})]})]})};const HomelabView=({section})=>{const _components={a:`a`,..._provideComponents()};const graph=__snippet_DATA_14dwlcs.graphs[section];return _jsxs(`div`,{className:`hi-root not-prose`,children:[section===`hardware`?_jsx(__snippet_Hardware_14dwlcs,{}):section===`services`?_jsx(__snippet_Services_14dwlcs,{}):graph?_jsx(__snippet_Graph_14dwlcs,{graph,id:`infra-`+section}):null,section===`security`\u0026\u0026_jsx(`p`,{className:`hi-note`,children:`Most app namespaces have no blanket default-deny policy. Mac firewall and FileVault are off; SIP is on.`}),section===`inference`\u0026\u0026_jsx(`p`,{className:`hi-note`,children:`No local model server observed. No inference request sent.`}),_jsxs(`div`,{className:`hi-observed`,children:[`Observed 4 Nov 2026, 03:15 AEST · `,_jsx(_components.a,{href:`https://apps.augustin.ai/homelab-infra/#`+section,children:`Open web app`})]})]})};function _createMdxContent(props){const _components={a:`a`,p:`p`,..._provideComponents(),...props.components},{_MdxComponentBoundary}=_components;if(!_MdxComponentBoundary)_missingMdxReference(`_MdxComponentBoundary`,true);return _jsxs(_Fragment,{children:[_jsx(_MdxComponentBoundary,{name:`HomelabView`,children:_jsx(HomelabView,{section:`hardware`})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`/infrastructure/node-prep`,children:`node preparation`}),` and `,_jsx(_components.a,{href:`/infrastructure/recovery`,children:`recovery`}),` for host setup. Intel GPU shares are scheduling slots, not additional physical GPUs.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{__snippet_DATA_14dwlcs,__snippet_placeNode_14dwlcs,__snippet_routeEdge_14dwlcs,__snippet_Links_14dwlcs,__snippet_MachineArt_14dwlcs,__snippet_Hardware_14dwlcs,__snippet_Graph_14dwlcs,__snippet_dependencyGraph_14dwlcs,__snippet_Services_14dwlcs,HomelabView,default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Hardware","description":"Three k3s nodes and a separate Mac.","href":"/infrastructure/hardware"}}},"mdxSourceWithNoJs":null,"noJsSplices":[[157,45565,"undefined;const __snippet_placeNode_14dwlcs=()=>null;const __snippet_routeEdge_14dwlcs=()=>null;const __snippet_Links_14dwlcs=()=>null;const __snippet_MachineArt_14dwlcs=()=>null;const __snippet_Hardware_14dwlcs=()=>null;const __snippet_Graph_14dwlcs=()=>null;"],[45605,48375,"()=>null;const __snippet_Services_14dwlcs=()=>null;const HomelabView=()=>null;fu"]]},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":[],"subdomain":"augustin","siteName":"Augustin's Homelab","title":"Hardware - Augustin's Homelab","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-04T23:37:49.115Z","originalFileLocation":"infrastructure/hardware.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Three k3s nodes and a separate Mac.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Augustin\u0026#x27;s Homelab\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/augustin/_generated/favicon/apple-touch-icon.png?v=3\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/augustin/_generated/favicon/favicon-32x32.png?v=3\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/augustin/_generated/favicon/favicon-16x16.png?v=3\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/augustin/_generated/favicon/favicon.ico?v=3\">\u003cmeta data-mint-head property=\"og:title\" content=\"Hardware - Augustin\u0026#x27;s Homelab\">\u003cmeta data-mint-head property=\"og:description\" content=\"Three k3s nodes and a separate Mac.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Augustin\u0026#x27;s Homelab\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.augustin.ai/infrastructure/hardware\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://augustin.mintlify.site/_mintlify/api/og/v2?division=Homelab\u0026amp;title=Hardware\u0026amp;description=Three+k3s+nodes+and+a+separate+Mac.\u0026amp;theme=7c3f8c7eeb3487e555989cd9\u0026amp;signature=4434bc05be21c53e2abdf179aab43b5eea59fb29ff8ffe14b55b3caf8b2e0488\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Hardware - Augustin\u0026#x27;s Homelab\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Three k3s nodes and a separate Mac.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://augustin.mintlify.site/_mintlify/api/og/v2?division=Homelab\u0026amp;title=Hardware\u0026amp;description=Three+k3s+nodes+and+a+separate+Mac.\u0026amp;theme=7c3f8c7eeb3487e555989cd9\u0026amp;signature=4434bc05be21c53e2abdf179aab43b5eea59fb29ff8ffe14b55b3caf8b2e0488\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"https://mintlify.s3.us-west-1.amazonaws.com/augustin/_generated/favicon/browserconfig.xml?v=3\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Augustin\u0026#x27;s Homelab\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#0066FF\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.augustin.ai/infrastructure/hardware\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/infrastructure/hardware.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.augustin.ai/#organization\",\"name\":\"Augustin's Homelab\",\"url\":\"https://docs.augustin.ai\"},{\"@type\":\"WebSite\",\"@id\":\"https://docs.augustin.ai#website\",\"name\":\"Augustin's Homelab\",\"url\":\"https://docs.augustin.ai\",\"publisher\":{\"@id\":\"https://docs.augustin.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.augustin.ai/infrastructure/hardware#webpage\",\"url\":\"https://docs.augustin.ai/infrastructure/hardware\",\"name\":\"Hardware\",\"description\":\"Three k3s nodes and a separate Mac.\",\"dateModified\":\"2026-11-04T23:37:49.115Z\",\"isPartOf\":{\"@id\":\"https://docs.augustin.ai#website\"},\"breadcrumb\":{\"@id\":\"https://docs.augustin.ai/infrastructure/hardware#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.augustin.ai/infrastructure/hardware#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Augustin's Homelab\",\"item\":\"https://docs.augustin.ai\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Hardware\",\"item\":\"https://docs.augustin.ai/infrastructure/hardware\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.augustin.ai/infrastructure/hardware#article\",\"headline\":\"Hardware\",\"name\":\"Hardware\",\"description\":\"Three k3s nodes and a separate Mac.\",\"url\":\"https://docs.augustin.ai/infrastructure/hardware\",\"mainEntityOfPage\":{\"@id\":\"https://docs.augustin.ai/infrastructure/hardware#webpage\"},\"dateModified\":\"2026-11-04T23:37:49.115Z\",\"publisher\":{\"@id\":\"https://docs.augustin.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.augustin.ai#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Augustin's Homelab\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"Augustin's Homelab\"},\"provider\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","agentPointerHref":"/infrastructure/hardware.md","siteName":"Augustin's Homelab","nav":{"global":null,"tabs":[{"tab":"Docs","groups":[{"group":"Homelab","pages":[{"title":"Hardware","href":"/infrastructure/hardware"},{"title":"Services","description":"Jellyfin, mail, home automation and the rest of the cluster.","href":"/infrastructure/services"},{"title":"Agents","href":"/infrastructure/agents"},{"title":"Inference","href":"/infrastructure/inference"},{"title":"Network","href":"/infrastructure/networking"},{"title":"Security","href":"/infrastructure/security"}]},{"group":"Operations","pages":[{"title":"Adding people","href":"/adding-people"},{"title":"Agents and daily use","href":"/infrastructure/agents-operations"},{"title":"Backups","href":"/infrastructure/backups"},{"title":"Monitoring","href":"/infrastructure/monitoring"},{"title":"Disaster Recovery Playbook","href":"/infrastructure/recovery"},{"title":"Node Prep (bare OS → cluster-ready)","href":"/infrastructure/node-prep"}]},{"group":"About","pages":[{"title":"Welcome","href":"/welcome"}]}]},{"tab":"Blog","pages":[{"title":"Blog","href":"/the-cartographer-of-vanishing-things"}]}]},"basePath":"","title":"Hardware - Augustin's Homelab","buildId":"dpl_596ePT575z4qnAFksq1biRW97aLY","deploymentId":"dpl_596ePT575z4qnAFksq1biRW97aLY","dynamics":[],"chunks":[]}