Repository navigation
Artifacts
Artifacts are the core abstraction in HomePilot. Every change the AI proposes to your infrastructure is captured as an artifact — a structured Markdown file with YAML frontmatter that describes what to do, what target to do it on, and how to verify it worked.
The AI never mutates infrastructure directly. It drafts a fully-specified plan (an artifact); you review it, approve it, and then HomePilot executes it. This gives you:
- Review before execution — you see exactly what will happen
- Audit trail — every transition is recorded
- Rollback — Proxmox snapshots and rollback specs let you undo changes
- Survivability — artifacts are plain Markdown; readable without HomePilot
~/.hp/artifacts/YYYY/MM/YYYY-MM-DD-<slug>[-<hash6>].md
Examples:
2026-05-06-deploy-jellyfin-lxc.md-
2026-05-06-deploy-jellyfin-lxc-a3f201.md(collision) 2026-05-06-pve-authentik-oidc.md
Every artifact is a Markdown file with YAML frontmatter:
---
id: 2026-05-06-deploy-jellyfin-lxc
kind: proxmox-api-sequence
intent: "Deploy Jellyfin LXC on Proxmox"
status: proposed
mutating: true
target:
kind: lxc
vmid: 142
node: pve1
host: jellyfin-lxc
idempotence: via-precheck
produced_by:
session: chat-2026-05-06-abc
agent: claude-opus
user: admin
at: "2026-05-06T14:32:00Z"
hash: sha256:a3f201...
---
# Deploy Jellyfin LXC on Proxmox
## Plan
Create a new LXC container running Debian 13, install Jellyfin,
configure hardware transcoding, and start the service.
## Spec
```yaml proxmox-api-spec
steps:
- id: create-lxc
method: POST
path: /nodes/{{ target.node }}/lxc
body:
vmid: "{{ target.vmid }}"
ostemplate: "local:vztmpl/debian-13-standard_13.0-1_amd64.tar.zst"
hostname: "{{ target.host }}"
memory: 4096
cores: 4
net0: "name=eth0,bridge=vmbr1,ip=dhcp"
precheck:
method: GET
path: /nodes/{{ target.node }}/lxc/{{ target.vmid }}/status/current
skip_if: "response.status_code == 200"
on_error: halt
- id: start-lxc
method: POST
path: /nodes/{{ target.node }}/lxc/{{ target.vmid }}/status/start
precheck:
method: GET
path: /nodes/{{ target.node }}/lxc/{{ target.vmid }}/status/current
skip_if: "response.json['data']['status'] == 'running'"
on_error: haltsteps:
- id: stop-lxc
method: POST
path: /nodes/{{ target.node }}/lxc/{{ target.vmid }}/status/stop
on_error: continue
- id: delete-lxc
method: DELETE
path: /nodes/{{ target.node }}/lxc/{{ target.vmid }}
on_error: continue
## Frontmatter Schema
### Always Required
| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Matches filename basename |
| `kind` | enum | See Artifact Kinds below |
| `intent` | string | One-line description, max 200 chars |
| `status` | enum | See Lifecycle below |
| `mutating` | bool | `true` for all except `kb-note` |
| `produced_by` | object | `{ session, agent, user, at }` |
| `hash` | string | `sha256:<hex>` of the body |
### Required for Mutating Kinds
| Field | Type | Description |
|-------|------|-------------|
| `target` | object | See Target Object below |
| `idempotence` | enum | `via-precheck`, `declared-natural`, or `replay-only` |
### Set by Lifecycle Transitions
| Field | Set When |
|-------|----------|
| `approved_by` | On approve: `{ user, at, reason }` |
| `applied_at` | On apply (success) |
| `failed_at`, `failure_reason` | On apply (failure) |
| `supersedes` | At propose time (references older artifacts) |
| `superseded_by` | When superseded |
| `rejected_by` | On reject |
| `revoked_by` | On revoke |
## Target Object
```yaml
target:
kind: vm | lxc | node | cluster | service | network | global
host: <hostname> # optional, inventory name
vmid: <int> # required for vm/lxc
node: <pve-node-name> # required for vm/lxc/node; forbidden for cluster
service: <service-name> # required for service
network: <bridge-or-vlan> # required for network
kind |
Required | Optional |
|---|---|---|
vm |
vmid, node
|
host |
lxc |
vmid, node
|
host |
node |
node |
— |
cluster |
(none; node MUST NOT be set) |
— |
service |
service |
host |
network |
network |
node |
global |
(none) | — |
┌─────────┐
┌────►│ proposed │
│ └────┬────┘
│ │ approve / reject
│ ┌────┴──────┐
│ ▼ ▼
│ approved rejected ──── (terminal)
│ │
│ │ apply
│ ┌──┴───┐
│ ▼ ▼
│ applied failed ──► approve (retry)
│ │
│ │ supersede
│ ▼
│ superseded ──── (terminal)
│
└── revoke ──► revoked ──── (terminal, triggers rollback)
| From | To | Trigger |
|---|---|---|
| (none) | proposed |
propose_artifact(spec) |
proposed |
approved |
hp artifacts approve <id> |
proposed |
rejected |
hp artifacts reject <id> (terminal) |
approved |
applied |
hp artifacts apply <id> (executor success) |
approved |
failed |
Executor error during apply |
failed |
approved |
hp artifacts approve <id> (retry, only if idempotent) |
applied |
superseded |
Another artifact supersedes it (terminal) |
applied |
revoked |
hp artifacts revoke <id> (triggers rollback) |
kind: kb-note artifacts skip the approval gate entirely — they auto-apply on propose. No approved_by, no executor run, no apply log.
A rejected artifact stays for history but cannot be revived. Create a new artifact to re-do the work.
Runs an Ansible playbook on the target host via the SSH jump server.
-
Idempotence:
declared-natural(Ansible's promise) -
Spec block:
```yaml ansible-spec ```— valid Ansible playbook list -
Rollback block:
```yaml ansible-rollback ```— optional
Executes an ordered sequence of Proxmox REST API calls. Each mutating step requires a precheck to verify idempotence.
-
Idempotence:
via-precheck(default, required for mutating steps) -
Spec block:
```yaml proxmox-api-spec ``` -
Rollback block:
```yaml proxmox-api-rollback ```
steps:
- id: step-name
method: POST | GET | PUT | DELETE
path: /nodes/{{ target.node }}/lxc/{{ target.vmid }}/...
body: { ... } # optional
precheck: # required for mutating steps
method: GET
path: /nodes/...
skip_if: "response.status_code == 200"
on_error: halt | continue # default: haltSame shape as proxmox-api-sequence but targets adopted services (e.g., Authentik). Each step resolves credentials from the vault by name.
-
Idempotence:
via-precheck(required) -
Spec block:
```yaml http-spec ``` -
Rollback block:
```yaml http-rollback ```
Run a bash script on a managed host via SSH. Last resort for operations that don't fit structured kinds.
-
Required:
## Idempotence preamblesection explaining how the script is idempotent -
Spec block:
```bash shell-spec ``` -
Rollback block:
```bash shell-rollback ```— optional but encouraged - Restriction: target host cannot be a Proxmox node itself
References other artifacts and runs them in topological order. Used when a single intent spans multiple kinds.
-
Spec block:
```yaml composite-spec ``` - Steps reference sub-artifact IDs
- Approving a composite cascades to its sub-artifacts
- Editing a sub-artifact invalidates composite approval
Knowledge base entry. Non-mutating. Auto-applies on proposal.
-
Note kinds:
note(durable fact),policy(preference),decision(recorded choice)
| Value | Meaning | Required for |
|---|---|---|
via-precheck |
Spec includes prechecks that verify current state before each step |
proxmox-api-sequence, http-sequence
|
declared-natural |
Agent claims the spec is naturally idempotent (e.g., Ansible modules) |
ansible-playbook, shell-script
|
replay-only |
Not idempotent; safe to apply once only. Executor refuses replay without --force
|
Any kind, rare |
The hash field covers the artifact body (everything after the frontmatter ---). It ensures the content you approved is exactly what gets applied.
- Computed at
propose_artifact - Re-verified at
approve— mismatch refuses approval - Re-verified at
apply— mismatch aborts withtamperederror - Line endings normalized to LF via
.gitattributes
hp artifacts list # list all artifacts
hp artifacts show <id> # show artifact detail
hp artifacts approve <id> # approve a proposed artifact
hp artifacts reject <id> # reject a proposed artifact
hp artifacts apply <id> # apply an approved artifact
hp artifacts apply <id> --approve # approve + apply atomically
hp artifacts edit <id> # open in editor
hp artifacts revoke <id> # revoke an applied artifact (triggers rollback)
hp artifacts drift <id> # check drift for an applied artifact
hp artifacts push # push artifact git repo to remote
hp artifacts pull # pull artifact git repo from remote- Architecture — System architecture and MCP tools
- API Reference — REST endpoints for artifact management