Find a file
oskar 71a7af5b3f fix(control-plane): unwedge incidents that never get service_healthy
_resolve_incident() only ever fires from process_event() on a
service_healthy/service_recovered event. A service that is removed,
renamed, or was only ever a one-off test never emits that event again,
so its incident stays "active" in world/incidents.json forever — this
is what left 5 incidents wedged on VPS until a manual on-node edit
during the 2026-08-26 recon session (docs/sessions/2026-08-26.md).

Two independent unwedging mechanisms, both in observer._prune_stale_world
(runs every cycle, so no new event is required to trigger either):

(a) Time-based fallback: any active incident with last_occurrence older
    than INCIDENT_STALE_RESOLVE_SECS (env, default 24h) auto-resolves
    with resolved_reason="auto_stale_no_events_24h". Unlike the existing
    orphan case (Case 2, 5-min guard, only unlinked incidents), this
    also clears a service's lingering incident_id link — that link is
    exactly what a decommissioned service's incident never gets a
    chance to clear via the normal event path.

(b) Manual path: an operator touches
    world/resolve-requests/<incident-id>; the observer consumes the
    flag file each cycle, force-resolves with resolved_reason=
    "manual_operator", and always removes the flag (even for an
    unknown/already-resolved id) so a mistyped flag can't sit forever
    looking unprocessed.

    Chose a flag file over adding a mutation endpoint to operator_ui.py:
    /action/mutate only knows actions/<status>/<id>.json, there is no
    incidents equivalent, and world/incidents.json is exclusively
    observer-owned (rewritten wholesale every cycle by _save_world) —
    a second writer (the HTTP handler thread) would race the observer's
    own writes. A flag file needs no new HTTP surface and reuses the
    same "operator drops a file, the owning process consumes it"
    pattern the actions pending/approved queue already uses. Smaller
    diff, no new attack surface on a server with no auth on writes.

Tests added to test_incident_lifecycle.py: stale-resolve past the
threshold (service still linked), negative case (fresh active incident
stays active), configurable threshold, manual-flag resolve + flag
removal, flag for an unknown incident, flag for an already-resolved
incident. Full control-plane suite: 179 passed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WDKj5LRY8vdQMx57dfNnu
2026-08-26 21:05:38 +02:00
.claude/skills feat(kb): skill i skrypt do pisania dokumentow kb/ (OKF authoring) 2026-08-26 17:05:04 +02:00
backups/zigbee Add Zigbee coordinator backup 2026-05-14 18:24:26 +02:00
docs/sessions docs(kb): incydent 20 dni ciszy kb-mail-sync + session log 2026-08-26 20:39:45 +02:00
dotfiles add shared zshrc 2026-05-10 20:52:44 +02:00
hardware/esp/ir-ac-ha-integration feat(kb): przenosiny type=service do kb/services/ (13 plikow, bez SPLIT) 2026-08-04 16:58:04 +02:00
hosts feat(mail-sync): scheduler PIHA, takt kb-ingest, runbook i dokumentacja 2026-08-06 15:30:57 +02:00
inventory feat(supervisor): duty-cycle nodes — liveness transitions logged, not actioned 2026-08-05 13:48:29 +02:00
jobs feat(mail-sync): scheduler PIHA, takt kb-ingest, runbook i dokumentacja 2026-08-06 15:30:57 +02:00
kb docs(kb): incydent 20 dni ciszy kb-mail-sync + session log 2026-08-26 20:39:45 +02:00
packages feat(mail-imap-sync): job przyrostowki + wpiecie w tor body-ingest 2026-08-06 15:30:57 +02:00
scripts fix(control-plane): unwedge incidents that never get service_healthy 2026-08-26 21:05:38 +02:00
services fix(control-plane): unwedge incidents that never get service_healthy 2026-08-26 21:05:38 +02:00
.codex Document current homelab state 2026-04-15 17:37:25 +02:00
.gitignore feat(kb): generator publicznej warstwy KB (gen_pages.py) 2026-08-04 17:57:15 +02:00
.mcp.json feat(ha-mcp): read-only MCP server (faza 2a) 2026-07-30 16:47:27 +02:00
CLAUDE.md fix(kb): przepiecie wszystkich odwolan wewnetrznych po migracji 2026-08-04 16:58:46 +02:00
codex_context Add session context state 2026-04-20 22:10:39 +02:00
codex_context.yaml add shared context lock 2026-05-05 17:25:50 +02:00
deploy_agent.py Add deploy escalation output 2026-04-22 22:08:26 +02:00
ollama_client.py Initial shared homelab agent workspace 2026-05-03 19:37:40 +02:00
README.md fix(kb): przepiecie wszystkich odwolan wewnetrznych po migracji 2026-08-04 16:58:46 +02:00
start-aider.sh Initial shared homelab agent workspace 2026-05-03 19:37:40 +02:00
start-codex.sh Initial shared homelab agent workspace 2026-05-03 19:37:40 +02:00
sync-context.sh add shared context lock 2026-05-05 17:25:50 +02:00
update-context.md Initial shared homelab agent workspace 2026-05-03 19:37:40 +02:00

Homelab Codex

GitOps-lite orchestration for a distributed homelab environment.

Architecture

The homelab consists of several nodes connected via a Tailscale internal mesh.

Host Role Description
SATURN Primary Node Development, orchestration, and git source of truth (commit node).
SOLARIA Compute Node GPU, inference, and heavy compute workloads.
PIHA Infra Node Core infrastructure services, automation, and monitoring.
VPS Edge Node Public ingress, reverse proxy, and edge services.

Agent System

The homelab uses a multi-agent orchestration model with human-in-the-loop for destructive actions:

Agent Node Role
stability-agent all nodes Per-node watchdog — monitors Docker, disk, Tailscale, MQTT; emits events
node-agent all nodes Publishes container health events to Redis pub/sub
observer VPS Synthesizes world state from events into /opt/homelab/world/*.json
supervisor VPS Detects drift between desired and actual state; writes pending actions
planner-agent SOLARIA LLM-powered diagnosis — listens to Redis, proposes remediation actions
executor VPS Executes actions only after operator approval
operator-ui + telegram-bot VPS / PIHA Operator reviews and approves/rejects pending actions

Action approval flow: pending/ → operator approves → approved/ → executor runs.

Repository Structure

Getting Started

  1. Standardization: Follow the Infrastructure Standards.
  2. Deployment: See Deployment Conventions for how to roll out changes.
  3. SATURN: Remember that SATURN is the only node where commits should be made.

Documentation Index


Note: This repository documents the state of the homelab. Runtime state lives outside the repository in /opt/homelab.