This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Reference

Command, contract, template, and acceptance references.

Use this section when you already know the workflow and need exact command or schema details.

1 - CLI

The complete ainfra command surface.
ainfra init [--name NAME] [--template TEMPLATE]
  [--environment ENVIRONMENT] [--format text|json]
ainfra validate [<path-or-template>] [--input INPUT]
  [--format text|json]
ainfra doctor [--input INPUT | --environment ENV] [--format text|json]
ainfra plan [<template> --input INPUT | --environment ENV]
  [--destroy] [--format text|json]
ainfra apply [<template> --input INPUT | --environment ENV]
  --approve PLAN_ID
ainfra up --environment ENV --approve PLAN_ID --known-hosts FILE
  [--format json|yaml]
ainfra destroy [<template> --input INPUT | --environment ENV]
  --approve-destroy PLAN_ID
ainfra down --environment ENV --approve-destroy PLAN_ID
ainfra outputs [<template> | --environment ENV] --run PLAN_ID
  [--format json|yaml]
ainfra configure [<template> | --environment ENV] --run PLAN_ID
  --known-hosts FILE [--check]
ainfra status --environment ENV [--format text|json]
ainfra legacy inspect [--root PYTHON_REPOSITORY] [--format text|json]
ainfra inventory --output OUTPUT --destination DESTINATION

init

Initializes the current directory without contacting a provider or invoking OpenTofu or Ansible. It creates ainfra.yaml, ainfra.lock, and one example under environments/, then adds .ainfra/ to .gitignore.

Initialization preflights every primary file and refuses to overwrite any of them. There is intentionally no force flag. The lock pins the selected built-in template’s name, version, source, and content digest.

validate

Validates an InfrastructureTemplate, TemplateInput, or InfrastructureOutput document. It does not resolve credentials or mutate infrastructure. With no target, it discovers the nearest ancestor ainfra.yaml and validates the project, lockfile, environment references, template digest, contracts, and policy.

doctor

Reports local dependency and configuration readiness without mutation. Providing --input adds checks that depend on the target environment’s backend mode and capabilities. --environment selects project mode and checks the configured input plus compatible OpenTofu and Ansible versions. The two selectors are mutually exclusive.

plan

Validates the template and input, invokes OpenTofu planning, applies policy checks, and emits a reviewable plan ID. The built-in template is materialized into an isolated per-plan workspace. --destroy creates the corresponding destruction review without bypassing the exact-plan gate.

Project mode uses --environment ENV and discovers the nearest ancestor ainfra.yaml. Explicit compatibility mode remains TEMPLATE --input INPUT; mixing selectors fails before any subprocess.

apply

Applies only the plan identified by --approve, from its retained isolated workspace. A stale, absent, changed, or mismatched identifier fails closed before an infrastructure process starts.

Project plans use the ainfra.plan/v1alpha2 protocol and bind the canonical project root plus the exact bytes of ainfra.yaml and ainfra.lock. Legacy explicit records remain v1alpha1; records cannot cross-authorize between the two modes.

destroy

Destroys only through the exact destroy plan identified by --approve-destroy. The implementation applies that reviewed plan rather than running an unreviewed direct destroy command.

up

Completes a previously reviewed project apply plan. It does not create or select a plan. After rechecking local readiness and the exact approval ID, it composes apply, standardized output collection, Ansible configuration, and Ansible check-mode verification. Successfully completed stages are resumed without repeating their mutations; interrupted or failed stages require manual recovery.

The required --known-hosts file remains independent host-identity evidence. The resulting validated infrastructure output is emitted as JSON or YAML.

down

Applies only a previously reviewed project destroy plan. It never creates a destroy plan, reuses an apply approval, selects the latest plan implicitly, or invokes an unreviewed direct destroy command. After applying the exact plan, it runs a separate tofu state list verification and records destroyed only when no resources remain in the reviewed backend state.

outputs

Collects OpenTofu output for one exact successfully applied run, rejects sensitive or ownership-inconsistent values, and emits the validated, sanitized InfrastructureOutput. It never substitutes raw state or raw engine output for that contract.

configure

Builds a private-address inventory from one run’s validated output and invokes the retained Ansible playbook. --known-hosts must name an independently verified, non-group/world-writable host-key file. After a successful configuration, --check records a distinct check-mode verification stage; it never records configuration as applied.

inventory

Transforms a validated standardized output into an Ansible inventory at an explicit destination.

legacy inspect

Inspects Python-prototype .ainfra/runs/ evidence without invoking OpenTofu, Ansible, credential providers, or provider APIs and without writing files. It reports sanitized record identities, exact plan-byte integrity, and corrupt entry counts.

Legacy lifecycle state is always unknown. The command never imports a plan, synthesizes project bindings or lifecycle events, or recommends applying or destroying with an old ID. Machine output uses ainfra.legacy-inspection/v1alpha1 and always requires a new project-bound plan before normal project lifecycle can begin.

status

Reads only validated project files and durable local run evidence. It never invokes OpenTofu, Ansible, credential providers, DNS, or provider APIs.

The report classifies the latest project-bound run as planned, applied, output-collected, configured, verified, destroy-planned, destroyed, destroy-applied, partial, stale, corrupt, legacy, or none. Started operations without a matching success or failure event are partial; they are never assumed safe to retry. Machine output uses ainfra.status/v1alpha1 and includes sanitized checks and the next safe command or manual-recovery route.

2 - Contracts

Versioned schemas at the boundary between templates and consumers.

All schemas use JSON Schema draft 2020-12 and reject unknown fields.

ContractSourcePurpose
InfrastructureTemplate/v1alpha1schemas/template-manifest.v1alpha1.jsonTemplate engines, paths, capabilities, and invariants
TemplateInput/v1alpha1schemas/template-input.v1alpha1.jsonNon-secret operator intent and credential references
InfrastructureOutput/v1alpha1schemas/template-output.v1alpha1.jsonStable, non-secret handoff to downstream systems
ainfra.plan/v1alpha1schemas/plan-record.v1alpha1.jsonExact reviewed-plan binding for lifecycle authorization
ainfra.plan/v1alpha2schemas/plan-record.v1alpha2.jsonProject-bound lifecycle authorization
ainfra.run/v1alpha2schemas/run-record.v1alpha2.jsonImmutable run identity
ainfra.run-event/v1alpha1schemas/run-event.v1alpha1.jsonAppend-only lifecycle evidence
ainfra.status/v1alpha1schemas/status.v1alpha1.jsonSanitized local status output
ainfra.legacy-inspection/v1alpha1schemas/legacy-inspection.v1alpha1.jsonRead-only legacy evidence report

Compatibility

The apiVersion is locked through the v1 series. An incompatible v2 requires a full migration rather than silent coercion.

Validation behavior

  • Unsupported apiVersion and kind values fail.
  • Unknown properties fail.
  • Secret-shaped standard outputs fail.
  • Undeclared capabilities fail.
  • Template paths cannot escape the template directory.
  • Secret references describe a source but do not contain the secret.

Run:

ainfra validate DOCUMENT

Positive and negative fixtures live under tests/fixtures/contracts/.

Reviewed-plan records

A reviewed-plan record binds the intended operation to the selected template and version, environment identity, canonical input path and bytes, template tree, remote backend configuration, and generated OpenTofu plan bytes. Apply and destroy must reject any changed binding before starting an infrastructure process.

Explicit compatibility mode writes ainfra.plan/v1alpha1 and reads normal records created by the Python implementation. Project mode writes ainfra.plan/v1alpha2, adding the canonical project root and exact project configuration and lockfile paths and digests. The two modes cannot cross-authorize.

Approval identifiers are exactly 20 lowercase hexadecimal characters. Plan files must resolve beneath their corresponding .ainfra/runs/<PLAN_ID>/ directory.

Run records and events

run.json repeats only non-secret immutable plan identity. Lifecycle evidence is append-only and ordered by a contiguous sequence number. Configuration, check-mode convergence verification, and post-destroy zero-resource verification are distinct stages; timestamps are informational and never override event order. Failed events contain only a stable AINFRA-E* code and a sanitized recovery category.

The older ainfra.run/v1alpha1 apply/destroy marker remains legacy success evidence. It is not treated as a durable event history and is never upgraded silently.

3 - Templates

Bundled infrastructure templates and where to find them.

ainfra embeds its built-in templates in the release binary. Their reviewed source remains under templates/; each directory contains an ainfra-template.yaml manifest and a template-specific README.

TemplateSourcePurposeStatus
hetzner-kubernetes-baselinetemplates/hetzner-kubernetes-baselinePrivate-networked, hardened Debian 13 hosts prepared for a later Kubernetes installationInitial validated template

The binary does not currently use an external registry or download templates at runtime. Clone the repository only when you want to inspect or adapt source.

Inspect locally

find templates -mindepth 2 -maxdepth 2 -name ainfra-template.yaml -print
ainfra validate hetzner-kubernetes-baseline \
  --input templates/hetzner-kubernetes-baseline/inputs/example.input.yaml

The identifier supplied to the CLI is the directory name, not a filesystem path:

ainfra plan hetzner-kubernetes-baseline \
  --input /path/to/environment.input.yaml

For selection and extension guidance, see the template strategy and template authoring guide.

4 - Hetzner Kubernetes-ready baseline

The first pinned infrastructure template.

The baseline provisions one control-plane-capable Debian 13 host and optional workers on a narrow private network. It does not install Kubernetes.

OpenTofu creates:

  • a project-owned private network and subnet;
  • a narrowly scoped firewall;
  • registrations for operator-supplied SSH public keys;
  • Debian 13 servers;
  • public IPv4 or IPv6 attachments only when explicitly enabled.

Ansible configures:

  • secure SSH daemon policy;
  • nftables host firewall policy;
  • unattended security updates;
  • persistent journal and audit configuration;
  • Kubernetes-ready operating-system prerequisites.

Networking

Public IPv4 and IPv6 are independent and disabled in the standard input. Disabling IPv4 means no billable public IPv4 resource or attachment may exist. The generated inventory prefers private management addresses.

Image

The complete supported image set contains one value:

  • debian-13 — the official Hetzner Debian 13 image, updated within its major release and validated by this template.

Host verification

Before the first Ansible connection, verify each SSH host-key fingerprint through a trusted console or another out-of-band channel. Add that verified key to known_hosts.

The approved disposable live sequence performs:

  1. cloud-init schema validation;
  2. OpenTofu plan and apply;
  3. deterministic SSH host identity verification;
  4. Ansible check mode;
  5. Ansible apply;
  6. a second apply with zero changes;
  7. destroy;
  8. provider and state checks confirming zero resources.

Source layout

templates/hetzner-kubernetes-baseline/
├── ainfra-template.yaml
├── inputs/
├── tofu/
├── cloud-init/
└── ansible/

5 - Acceptance matrix

Evidence expected for the initial secure template release.
RequirementEvidence
Versioned strict contractsSchema and positive/negative fixture tests
Visible wrapper commandsCLI, runner, lifecycle, and adapter tests
No template hardcodingContract-driven discovery and fixtures
Pinned Hetzner templateProvider lock, image enum, validation
Secure SSH and keysSchema, policy, plan, and host tests
Safe stateBackend capability validation
Secret-free outputStrict schema, redaction, Gitleaks
Local validation gatesscripts/validate-all, scripts/test-all
Standalone Rust productNo Python package; installed-shell no-tool test
Disposable lifecycleApproved live apply, idempotence, and teardown
Clear portfolio boundariesREADME and architecture review
No unsafe donor behaviorNegative policy and plan tests
No GitHub workflowsRepository-policy test

Every release criterion maps to an automated local check or documented manual verification with sanitized evidence. A claim without one of those forms of evidence remains unverified.