Task Board
The live who's-doing-what. Agents claim an item (set Owner + Status) before starting, respect
Blocked-by, and mark done only after its automated, reproducible behavior test passes green
(definition-of-done.md, ../docs/14-testing-and-conformance.md).
Seeded from ../roadmap/phases.md + ../roadmap/workstreams.md.
This board is the one working surface agents may edit (claim items, update status, add
items/escalations). The specs, ADRs, and roadmap are not editable by agents (R-TEST-06) —
raise spec problems here as an OQ-* escalation for the human. Every "Prove …" task below is
an automated conformance test (co-owned with WS-TEST), not a manual demo.
Status values: todo · in-progress · blocked · review · done
Add new items at the bottom of the relevant phase; keep IDs stable.
Phase 0 — Foundations
| ID |
Task |
WS |
Serves |
Blocked-by |
Owner |
Status |
| T-0.1 |
Create implementation repo structure (platform/apps/catalog/clusters) |
WS-GITOPS |
R-GITOPS-02 |
— |
— |
todo |
| T-0.2 |
CI: lint + schema validation + build/dry-run gates |
WS-GITOPS |
R-GITOPS-01 |
T-0.1 |
— |
todo |
| T-0.3 |
Author ServiceDefinition schema + renderer contract |
WS-GITOPS |
R-GITOPS-02 |
T-0.1 |
— |
todo |
| T-0.4 |
Conformance harness: Chainsaw runner + reproducibility contract + JUnit + coverage report + CI merge gate |
WS-TEST |
R-TEST-01/02/03/04 |
T-0.1 |
— |
todo |
| T-0.5 |
L0 Kyverno policy gate (default-deny present, no plaintext secrets, schema-valid ServiceDefinitions) |
WS-TEST |
R-TEST-01, R-NET-01, R-SEC-01 |
T-0.4 |
— |
todo |
Phase 1 — dev/test Cluster Bring-up
| ID |
Task |
WS |
Serves |
Blocked-by |
Owner |
Status |
| T-1.1 |
OpenTofu libvirt module for 3 node VMs (+ Longhorn data disk) |
WS-INFRA |
R-ENV-01 |
— |
— |
todo |
| T-1.2 |
cloud-init baseline (users, SSH, sysctls, virt/Longhorn prereqs) |
WS-INFRA |
R-ENV-01 |
T-1.1 |
— |
todo |
| T-1.3 |
Ansible: k3s HA install, Cilium CNI, disable flannel/kube-proxy/Traefik |
WS-INFRA |
R-PLAT-01 |
T-1.2 |
— |
todo |
| T-1.4 |
Bootstrap Flux + SOPS age key |
WS-GITOPS/WS-SEC |
R-GITOPS-01, R-SEC-01 |
T-1.3 |
— |
todo |
| T-1.5 |
Prove node destroy/rebuild from IaC (no data loss) |
WS-INFRA |
R-ENV-01, R-STATE-01 |
T-1.4 |
— |
todo |
Phase 2 — Platform Core (net/storage/TLS/DNS/ingress)
| ID |
Task |
WS |
Serves |
Blocked-by |
Owner |
Status |
| T-2.1 |
Longhorn (3-replica StorageClass) + bulk external-mount indirection (media lives off-cluster, backing TBD — OQ-2 resolved) |
WS-STORAGE |
R-STATE-02/04 |
T-1.4 |
— |
todo |
| T-2.2 |
Default-deny network baseline (per-namespace) + Hubble |
WS-NET |
R-NET-01/03 |
T-1.3 |
— |
todo |
| T-2.3 |
Render dependencies → CiliumNetworkPolicy from ServiceDefinition |
WS-NET/WS-GITOPS |
R-NET-02 |
T-0.3, T-2.2 |
— |
todo |
| T-2.4 |
cert-manager + Let's Encrypt DNS-01 wildcard *.home.keithjackson.dev (blocked on OQ-4: Cloudflare token vs acme-dns) |
WS-SEC |
R-TLS-01/02/03 |
T-1.4, OQ-4 |
— |
blocked |
| T-2.5 |
ExternalDNS + Gateway API listeners (VIP via Cilium L2 announcement) + split-horizon (PiHole) foundation |
WS-NET |
R-DNS-01/02/03 |
T-2.4 |
— |
todo |
| T-2.6 |
Prove: default-deny (DNS-only probe), PVC survives rebuild, trusted cert, auto-DNS |
WS-NET/STORAGE/SEC |
R-NET/STATE/TLS/DNS |
T-2.1..2.5 |
— |
todo |
| T-2.7 |
Deploy Kyverno in-cluster as admission enforcer (same policies as the CI L0 gate) |
WS-TEST/WS-SEC |
R-SEC-02, R-NET-01, R-SEC-01 |
T-1.4, T-0.5 |
— |
todo |
Phase 3 — Egress & VPN (single WAN; no multi-WAN — OQ-1)
| ID |
Task |
WS |
Serves |
Blocked-by |
Owner |
Status |
| T-3.0 |
L3 fault-injection harness — in-cluster Chainsaw Job (CI-triggered, scoped test SA) using script/try/finally (force tunnel down, kill node, inject bad image, trigger restore) |
WS-TEST |
R-TEST-05, R-SEC-02 |
T-0.4 |
— |
todo |
| T-3.1 |
Egress classes; Cilium Egress Gateway wiring (steer vpn pods → gateway) |
WS-NET |
R-NET-04/05 |
T-2.2 |
— |
todo |
| T-3.2p |
Prereq: obtain ExpressVPN manual OpenVPN-UDP config + manual creds; store SOPS-encrypted |
WS-SEC |
R-NET-05 |
— |
— |
todo |
| T-3.2 |
Single shared in-cluster ExpressVPN gateway (OpenVPN UDP, active/standby) + centrally-enforced kill-switch (ADR-0012) |
WS-NET |
R-NET-05/06 |
T-3.1, T-3.2p |
— |
todo |
T-3.3 |
Edge-router multi-WAN split — out of scope (single WAN, dumb SOHO edge; OQ-1) |
WS-NET |
R-NET-04 |
— |
— |
won't-do |
| T-3.4 |
Prove: VPN IP egress, kill-switch fail-closed (central), egress-class flip via git |
WS-NET |
R-NET-05/06/07 |
T-3.0, T-3.2 |
— |
todo |
Phase 4 — Observability, Backup/DR & Updates
| ID |
Task |
WS |
Serves |
Blocked-by |
Owner |
Status |
| T-4.1 |
kube-prometheus-stack + Loki + Alloy + Alertmanager(email) |
WS-OBS |
R-OBS-01/02/03 |
T-2.1 |
— |
todo |
| T-4.2 |
Platform-health alerts (node/Longhorn/Flux/cert/VPN/backup) |
WS-OBS |
R-OBS-04 |
T-4.1 |
— |
todo |
| T-4.3 |
Velero + Longhorn off-cluster backup schedule (needs backup-target choice — S3/NFS endpoint) |
WS-STORAGE |
R-STATE-03 |
T-2.1, OQ-BKP |
— |
todo |
| T-4.4 |
DR drill: restore namespace + volumes from off-cluster backup |
WS-STORAGE |
R-STATE-03 |
T-4.3 |
— |
todo |
| T-4.5 |
Flux image-automation + Renovate + per-service update policy |
WS-UPDATE |
R-UPD-01/02/03 |
T-0.3, T-4.1 |
— |
todo |
| T-4.6 |
Prove: auto stable update on schedule, bad-update auto-rollback+alert, pin holds |
WS-UPDATE |
R-UPD-* |
T-4.5 |
— |
todo |
Phase 5 — IaaS Proof (KubeVirt)
| ID |
Task |
WS |
Serves |
Blocked-by |
Owner |
Status |
| T-5.1 |
Install KubeVirt + CDI; Longhorn-backed VM disks |
WS-VM |
R-PLAT-03 |
T-2.1, T-2.2 |
— |
todo |
| T-5.2 |
kind: vm ServiceDefinition path; run one representative VM |
WS-VM/WS-GITOPS |
R-PLAT-03/04 |
T-5.1, T-0.3 |
— |
todo |
| T-5.3 |
Prove: VM lifecycle via kubectl/virtctl, rebuild w/o data loss, default-deny+egress, guest auto-update |
WS-VM |
R-PLAT-03, R-NET-, R-UPD- |
T-5.2 |
— |
todo |
Phase 6 — Service Onboarding + C2
| ID |
Task |
WS |
Serves |
Blocked-by |
Owner |
Status |
| T-6.1 |
Onboard pihole (DNS underpinning) |
WS-APPS |
R-DNS-03 |
T-2.5 |
— |
todo |
| T-6.1a |
Onboard gitea early (bootstrapping-critical; self-hosts GitOps source + CI/CD) |
WS-APPS |
R-STATE-03 |
T-4.4 |
— |
todo |
| T-6.1b |
Migrate GitOps source local→Gitea; move CI to Gitea Actions (Kyverno gate + Chainsaw Job trigger; PR merge gate); off-cluster repo mirror |
WS-GITOPS |
R-GITOPS-01, R-TEST-03 |
T-6.1a |
— |
todo |
| T-6.2 |
Onboard plex (bulk tier + public exposure) |
WS-APPS |
R-STATE-04 |
T-2.6, T-6.1 |
— |
todo |
| T-6.3 |
Onboard qbittorrent, jackett (VPN + kill-switch) |
WS-APPS |
R-NET-05/06 |
T-3.4 |
— |
todo |
| T-6.4 |
Onboard sonarr, radarr (VPN + arr↔downloader allows) |
WS-APPS |
R-NET-02/05 |
T-6.3 |
— |
todo |
| T-6.5 |
Onboard seerr (allows to arr + plex) |
WS-APPS |
R-NET-02 |
T-6.2, T-6.4 |
— |
todo |
| T-6.6 |
Onboard nextcloud (DR-critical + backups) |
WS-APPS |
R-STATE-03 |
T-4.4 |
— |
todo |
| T-6.7 |
Onboard minecraft, unifi, semaphore, kasm |
WS-APPS |
app reqs |
T-2.6 |
— |
todo |
| T-6.8 |
C2 UI: Homepage root + Grafana + Headlamp + Flux status + auth |
WS-C2 |
R-C2-01/02 |
T-4.2, T-6.* |
— |
todo |
Phase 7 — Production Readiness (CLOSED until operator opens it)
| ID |
Task |
WS |
Serves |
Blocked-by |
Owner |
Status |
| T-7.1 |
Bare-metal provisioning checklist (design-only) |
WS-INFRA |
R-ENV-03 |
— |
— |
todo |
| T-7.2 |
prod overlay (no base edits) + cutover plan |
WS-INFRA/WS-GITOPS |
R-ENV-02 |
Phases 1–6 done |
— |
blocked |
| T-7.3 |
Full prod DR drill |
WS-STORAGE |
R-STATE-03 |
T-7.2 |
— |
blocked |
Open questions
| OQ |
Question |
Blocks |
Status |
| OQ-1 |
WAN count + edge router |
— |
✅ resolved: 1 WAN, dumb SOHO edge; multi-WAN out of scope; VPN + segmentation in-cluster |
| OQ-2 |
Bulk-media home |
— |
✅ resolved: media outside cluster, backing TBD later (not blocking) |
| OQ-3 |
VPN provider/protocol |
— |
✅ resolved: ExpressVPN, single shared in-cluster tunnel, OpenVPN UDP (ADR-0012) |
| OQ-4 |
DNS-01 challenge access |
T-2.4, T-2.5 |
⛔ OPEN — Cloudflare API token (Option A, recommended) vs acme-dns delegation (Option B) |
| OQ-BKP |
Off-cluster DR backup target (S3/NFS endpoint) |
T-4.3 |
⛔ OPEN — needed by Phase 4, not Phase 2 |