Skip to content

Architecture

ollikurki edited this page May 20, 2026 · 1 revision

Architecture

HomePilot is a single-binary Python service (FastAPI) backed by SQLite, with an MCP server frontend, an age-encrypted vault, and an artifact store backed by git.

Components

MCP Server

The MCP (Model Context Protocol) server is the primary interface for AI clients. It supports two transports:

  • stdio — for local use (AI client on the same machine)
  • HTTP (StreamableHTTP) — for remote use (AI client connects over the network)

The MCP server exposes tools that AI clients can call to:

  • Query inventory (hosts, services, networks)
  • Search the knowledge base
  • Propose, approve, and apply artifacts
  • Read files or execute commands on managed hosts (read-only)
  • Check artifact drift

Core Services

Service Description
ArtifactLifecycle Manages artifact state transitions (propose → approve → apply → revoke)
ArtifactExecutor Dispatches artifact execution based on kind (Ansible, Proxmox API, HTTP, shell, composite)
KBService Knowledge base with vector + keyword search, backed by sqlite-vec
InventoryService Periodic reconciler that pulls host/service data from Proxmox and SSH guests
VaultManager Manages age-encrypted secrets with passphrase-derived key
EventBus Publishes SSE events for lifecycle transitions; delivers to registered webhooks

Data Layer

~/.hp/
├── homepilot.db          SQLite: hosts, services, artifacts index,
│                         KB entries (+ sqlite-vec for embeddings),
│                         audit log, webhook deliveries
├── artifacts/
│   └── YYYY/MM/YYYY-MM-DD-<slug>-<hash>.md   one file per artifact
│                         frontmatter (YAML) + body (Markdown)
└── vault/
    ├── master.protected  age-encrypted master identity
    └── secrets/          per-secret .age files
        ├── pve-token.age
        └── <service>.age

Vault encryption uses pyrage (pure Python age implementation). No system age binary is required. The master identity is protected with AES-256-GCM derived from the vault passphrase.

Data Flow

Inventory Reconciler

  1. Pulls host/VM/LXC data from Proxmox REST API
  2. Optionally connects to guests via SSH jump server
  3. Stores results in SQLite (hosts, services tables)
  4. Runs on configurable interval (default: 300 seconds)

Artifact Lifecycle

AGENT                                    YOU
──────────────────────────────────────────────────
1. READ      query_inventory, search_kb
             → Agent builds context

2. PROPOSE   propose_artifact(spec)
             → Artifact written with status: proposed

3. REVIEW    hp artifacts show <id>
             hp artifacts approve <id>    → status: approved
             hp artifacts reject <id>     → status: rejected (terminal)

4. APPLY     hp artifacts apply <id>
             → ArtifactExecutor._dispatch() runs the spec
             → Before mutating: Proxmox snapshot (if applicable)
             → Dispatch by kind:
                 ansible-playbook    → playbook via SSH jump server
                 proxmox-api-seq     → ordered Proxmox REST calls
                 http-sequence       → ordered calls to adopted services
                 shell-script        → exec on guest via SSH
                 composite           → ordered list of sub-artifacts
                 kb-note             → write to KB (auto-applied, no exec)

                                          │
                                    status: applied
                                    or status: failed
                                          │
                                    Snapshot pruned
                                    Audit entry written

5. REVOKE    hp artifacts revoke <id>  (applied → revoked)
             → If Proxmox snapshot exists: VM rolled back automatically
             → Artifact status: revoked, snapshot deleted

Event Pipeline

Every artifact transition and drift detection emits an SSE event via the EventBus. Connected clients stream these at GET /events.

Registered webhooks receive the same events as outbound HTTP POST deliveries with HMAC-SHA256 signatures.

All state transitions also write an append-only audit_log table in SQLite.

MCP Tools Reference

Tool Mutates? Scope Description
query_inventory no read List hosts/services/networks from DB
refresh_inventory no read Re-pull inventory from Proxmox + SSH
get_environment_doc no read Fused doc for a target
query_artifacts no read Find artifacts by status, kind, target
get_artifact_status no read Detailed status of one artifact
search_kb no read Vector + keyword search over KB
proxmox_api_read no read GET-only Proxmox REST call
http_call_read no read GET-only call to adopted services
read_file_on_guest no read SFTP file read via jump server
exec_on_guest_readonly no read Whitelisted read-only SSH exec
check_artifact_drift no read Check if applied artifact has drifted
record_fact KB only write Write to KB (auto-applied, no approval)
propose_artifact triggers flow write Creates artifact with status: proposed
approve_artifact yes write Approve a proposed artifact

SSH Jump Server

The jump server relays SSH connections from HomePilot to managed hosts without exposing private keys to the backend container. It uses a TCP protocol with length-prefixed JSON framing.

HomePilot backend → jumpserver:50051 → SSH → managed guest

The jump server generates its own key pair. You add the public key to authorized_keys on each managed host. For security, PVE_NODE_NAMES can block SSH to Proxmox nodes.

Inventory Sources

Source Protocol Data Collected
Proxmox VE REST API (HTTPS) VMs, LXCs, nodes, storage, networks
SSH guests Via jump server Services, packages, configs, facts

Artifact Git Backup

Every artifact write is committed to a local git repo inside the data directory. Optionally push to a private GitHub repository:

HP_ARTIFACTS_REMOTE=git@github.com:org/homepilot-artifacts.git
HP_ARTIFACTS_SSH_KEY=/home/homepilot/.hp/artifacts_deploy

Push failures are non-fatal — HomePilot continues normally if the remote is unreachable.

See Also

Clone this wiki locally