Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

NXD is a pre-release infrastructure reconciler for Nix-authored desired state. It evaluates consumer-owned Nix modules into canonical JSON, plans changes, applies persisted plans, and verifies results through typed providers.

Current verified gates include:

  • standalone extraction;
  • core canonical contracts and fixture reconciliation;
  • built-in PVE BackupJob reconciliation;
  • a synthetic external-provider protocol trial.

Production use is not generally supported yet. Follow the compatibility matrix and feature evidence before relying on any behavior.

Quick start with disposable fixtures

This tutorial uses checked-in synthetic fixtures only. It does not contact a real provider.

nix develop
cargo run -- validate --config-json tests/fixtures/canonical/minimal-site.json --format json
cargo run -- plan synthetic/example --config-json tests/fixtures/canonical/minimal-site.json --format json

For the Gate C backup-job fixture:

cargo run -- validate --config-json tests/fixtures/infrastructure/backup-job-site.json --format json

For Nix-authored sites, use the shared model and let NXD project canonical resources:

{
  nxd = {
    stack.name = "example";
    site.guests.web = {
      cluster = "lab";
      node = "pve-a";
      vmid = 120;
      tags = [ "production" ];
    };
    providers.pve.lab = {
      endpoint = "https://pve.example.invalid:8006";
      credentialBinding = "secret/pve-api";
    };
    secrets.bindings.pve-api = {
      resolver = "sops-age";
      document = "sites/example/pve.yaml";
      key = "token";
    };
    operations.production.includeTags = [ "production" ];
  };
}

Export it through nxd.lib.evalConfiguration as nxdConfigurations.<site>, then run nxd validate --source .#nxdConfigurations.<site>. Validation does not contact provider endpoints or resolve secret values.

Do not substitute production endpoints into fixture files. Real endpoint runs require an accepted runbook and explicit owner authorization.

Validate configuration

Use validate to parse and validate canonical JSON without contacting a provider:

nxd validate --config-json tests/fixtures/infrastructure/backup-job-site.json --format json

Validation proves local shape and reference constraints. It does not prove live provider compatibility, credentials, trust material, or target identity.

Architecture overview

NXD follows this boundary:

Nix modules -> canonical JSON -> validation -> plan -> persisted apply -> verify

Consumer repositories own topology, inventory, policy, and reviewed state. NXD owns schemas, planning, provider execution, reports, and reusable contracts.

See docs/nxd-integration-design.md for the full accepted design.

Safety model

NXD separates planning from mutation:

  • plan observes state and writes a reviewable proposal;
  • apply executes exactly one persisted plan;
  • verify checks live postconditions without producing mutation actions.

Secrets are represented by bindings in configuration and resolved only at runtime. Secret values must not appear in Nix, canonical JSON, plans, logs, events, argv, URLs, or committed documentation.

Plan cleanup is explicit and recoverable. nxd clean is a dry run unless --apply is supplied, and even then it archives only expired plans without approval, journal, or pin evidence. It never deletes reviewed evidence. Use --pin <plan> before long-lived review, --unpin <plan> when that protection is no longer needed, and --recover <archived-plan> to restore an archived plan. Recovery does not bypass plan expiry, compatibility, or approval checks.

Interactive durable enrollment workflows (deploy, switch --reenroll, and install/convert intents) ask once for the exact enrollment plan and a displayed, bounded same-session continuation across selected targets. The continuation is freshly planned, persisted, digested, and validated against the authorized scope before approval evidence is written. Any changed source, target, action, provider, secret, dependency, or risk stops for explicit review. Non-interactive and separate plan/apply workflows continue to require approval evidence for each plan digest.

Default plan output and interactive approval prompts render a target-grouped summary of pending work, listing destructive and identity-critical actions first and naming exact resources touched. --verbose renders the full action graph with identifiers and dependency edges.

CLI reference

Generated from the released Clap command model. Do not edit by hand.

CommandPurposeArguments and options
nxdLifecycle reconciler for Nix-authored infrastructure--debug, --verbose, --profile
nxd cleanPreview or archive expired disposable plans in a consumer .nxd workspace--root, --apply, --pin, --unpin, --recover
nxd bootstrapServe one validated, bounded PVE bootstrap plan
nxd bootstrap serveplan
nxd infoShow deployment-target metadata or its provider-observed endpointtarget, --ip, --wait, --source, --config-json, --format
nxd execExecute a reviewed argv vector through the configured target provider--target, --hosts, --source, --config-json, --format, --plan-only, --out, --parallel, command
nxd validateselections, --source, --config-json, --format
nxd show
nxd show configselections, --source, --config-json, --format
nxd show planpath, --format
nxd show runrun_id, --format
nxd planCreate a reviewed plan; --auto-apply continues through the shared mutation workflowselections, --source, --config-json, --format, --intent, --install-mode, --enrollment-strategy, --reactivate, --reenroll, --convert-from, --offline, --host-identity, --out, --auto-apply, --approval, --parallel
nxd applyplan, --approval, --run-id, --parallel
nxd verifyselections, --source, --config-json, --format
nxd switchErgonomic plan --intent switch --auto-apply target workflowtarget, --hosts, --source, --config-json, --format, --plan-only, --out, --parallel, --reactivate, --reenroll
nxd deployErgonomic plan --intent install --auto-apply target workflowtarget, --hosts, --source, --config-json, --format, --plan-only, --out, --parallel, --reinstall, --replace, --enrollment-strategy
nxd buildErgonomic plan --intent build-only --auto-apply target workflowtarget, --hosts, --source, --config-json, --format, --plan-only, --out, --parallel
nxd bootErgonomic plan --intent boot --auto-apply target workflowtarget, --hosts, --source, --config-json, --format, --plan-only, --out, --parallel
nxd testErgonomic plan --intent test --auto-apply target workflowtarget, --hosts, --source, --config-json, --format, --plan-only, --out, --parallel
nxd captureselections, --source, --config-json, --format, --out
nxd artifact
nxd artifact buildselector, --source, --config-json, --format, --out, --parallel
nxd artifact verifymanifest, --format
nxd approvalCreate or validate digest-bound approval evidence (never mutates targets)
nxd approval createCreate digest-bound approval evidence for a reviewed plan (no mutation)--plan, --out, --principal, --expires-at-unix, --format
nxd approval validateImport and validate approval evidence against a plan without applying--plan, --approval, --format
nxd dashboardBrowse selected configuration, reviewed plans, and run history locally--source, --config-json, --port, --open
nxd monitorrun_id, --format
nxd cancelrun_id, --format
nxd completionsshell

Provider resource reference

Generated from the released linked-provider metadata. Do not edit by hand.

ProviderKindSchema digestRequired fieldsFields
digitaloceandigitaloceanDropletsha256:2bac8f359929fc0b3bb8d72719e53f8daff773f226f52a72140225772a77f0d3kind, id, provider, secretBinding, hostname, region, size, imagedependsOn, deploymentTarget, hostname, id, image, kind, provider, region, secretBinding, size, state
headscaleheadscaleNodesha256:8c4d7fa77b908e9ea49bf17f66a5afabb8b4d2ee2f423d0eda595a194157cc90kind, id, provider, hostname, user, statedependsOn, deploymentTarget, hostname, id, kind, provider, state, user
headscaleheadscalePreauthKeysha256:b2e25273a98294a26e6fbb4f6d470f83b09c9319ec308e139cf3af5f1f2ce4e7kind, id, provider, hostname, user, secretBindingaclTags, dependsOn, deploymentTarget, ephemeral, expirationSeconds, hostname, id, kind, provider, reusable, secretBinding, user
headscaleheadscaleUsersha256:873d90b4d429c0e8622e7175a86b16c29a0ec88c72801e9586afd5ac54dc38c6kind, id, provider, namespacedependsOn, id, kind, namespace, provider
identitysshHostIdentitysha256:3f9d9b7a4f109a86a0c0957baff576051f35733da3c9db612b7b56593030b648kind, id, provider, algorithm, state, secretBinding, publicBindingalgorithm, dependsOn, deploymentTarget, id, kind, provider, publicBinding, secretBinding, state
identitytrustAnchorsha256:28944458af3f8c288b1e796e06f7e0153852f74aa51bb1d1b18aca6a77df9d64kind, id, provider, anchorType, publicContent, digestanchorType, dependsOn, digest, id, kind, provider, publicContent
pbsaccessGrantsha256:6c3d9ddd27ce418c8ae5331cc3653be4ea4b7c99c1756ad00600bd81f78e8371kind, id, provider, principal, path, roledependsOn, deploymentTarget, id, kind, labels, path, principal, propagate, provider, role, state
pbsaccessPrincipalsha256:d35f4551152e10635d68d4571ba60948aaa9390e068d49ab99b749fcdb8adc49kind, id, provider, backupServer, principalIdbackupServer, dependsOn, deploymentTarget, id, installBootstrap, kind, labels, principalId, principalType, provider, state, tokenSecretBinding
pbsbackupNamespacesha256:c12e1e6a652f4885601639bb230ca9407e973ee3fef8bc10fc74bdb77d6266d3kind, id, provider, datastore, namespacedatastore, default, dependsOn, deploymentTarget, id, kind, labels, namespace, operatorAccess, provider, state
pbsbackupRemotesha256:bc37e30edf353b53dd6df80ee5e3dc773ada8e813a9865d324641ec3677c722bkind, id, provider, backupServer, remoteIdaddress, authId, backupServer, certificateFingerprintBinding, dependsOn, deploymentTarget, fingerprint, host, id, kind, labels, provider, remoteId, state, tokenSecretBinding
pbsbackupServersha256:71a30cc93dc5089f70c4c2a1442c0074a706766a38e7732bbf1e018421ce55b8kind, id, provider, addressaddress, apiPort, dependsOn, deploymentTarget, guest, id, installAppliance, kind, labels, provider, pveNode, state
pbsbackupSnapshotsha256:434f23ab1e565f636dd30d5c466a07b391e46768a10f1385df5344ae8e805ad1kind, id, provider, datastore, namespace, backupType, backupId, maxAgeSecondsbackupId, backupType, datastore, dependsOn, deploymentTarget, id, kind, labels, maxAgeSeconds, namespace, proof, provider, state
pbsdatastoresha256:df0a681c7796065549c3b2277c4435b55e79b1903bdf875add8604140f18a439kind, id, provider, backupServer, datastoreIdbackingMount, backupServer, datastoreId, dependsOn, deploymentTarget, garbageCollectionSchedule, id, kind, labels, path, provider, state
pbspbsNotificationMatchersha256:4b81a411f930fa5513df085fe8a780a552c1eb68fee3c35cc252afccd4806bebkind, id, provider, server, matcherId, severities, targetsdependsOn, deploymentTarget, disableDefaultMatcher, id, kind, labels, matchMode, matcherId, provider, server, severities, state, targets
pbspbsNotificationTargetsha256:c77895993ed855c4fe7754e7b4f06cfff581e20916e0fd97e6618f39863d0375kind, id, provider, server, targetId, smtpServer, port, smtpMode, username, fromAddress, mailto, smtpSecretBindingauthor, dependsOn, deploymentTarget, fromAddress, id, kind, labels, mailto, port, provider, server, smtpMode, smtpSecretBinding, smtpServer, state, targetId, username
pbsprunePolicysha256:0cd7cbca858852080bd0363b37bfc63473053b8c254ad522e7dbe005193080b2kind, id, provider, policyId, datastore, scheduledatastore, dependsOn, deploymentTarget, id, keepDaily, keepLast, keepMonthly, keepWeekly, keepYearly, kind, labels, maxDepth, namespace, policyId, provider, schedule, state
pbssyncJobsha256:56ff65c9bb94f972d84e3014ff278b47ac5057d42c59bd9b66c7a3da81ff1f3akind, id, provider, remote, targetDatastoredependsOn, deploymentTarget, groupFilter, id, kind, labels, maxDepth, owner, provider, remote, remoteDatastore, remoteNamespace, removeVanished, schedule, state, targetDatastore, targetNamespace
pbsverificationPolicysha256:1d70c9bc0a456593a2ab14d5e193576c20e6fadd283de5aff5b4f1bfe0d3117akind, id, provider, policyId, datastore, scheduledatastore, dependsOn, deploymentTarget, id, ignoreVerified, kind, labels, maxDepth, namespace, outdatedAfterDays, policyId, provider, schedule, state
pvebackupJobsha256:fdacd8c718efb1a79610e1f8f598d2b357a8f0a3e77395cbe80005368a6c5643kind, id, provider, targetStorage, guests, schedulecompression, dependsOn, deploymentTarget, enabled, guests, id, kind, labels, mode, provider, schedule, state, targetStorage
pveguestsha256:4165126114ca5b6390ddc34c35fdc16bd2ee9573387d5c71aef980e9a7a872d9kind, id, provider, guestType, vmiddependsOn, deploymentTarget, endpointDiscovery, guestType, id, kind, labels, name, networks, node, onBoot, provider, provisioning, restoreSmoke, startupDown, startupOrder, startupUp, state, tags, vmid
pvenetworkAttachmentsha256:d8da16b89b7ed6365a25339fc164f1985af0eaf15e9c62ed669a99b41083c06akind, id, provider, node, ifacebridgePorts, dependsOn, deploymentTarget, id, iface, kind, labels, node, provider, state, vlanAware
pvepveAclsha256:7a5b916370029e823284d18f802c45de7e52f51c1a510205a9f695517f1c0adekind, id, provider, path, role, principaldependsOn, deploymentTarget, id, kind, labels, path, principal, propagate, provider, role, state
pvepveClustersha256:2bf535cda2a2c5ba4112170930928e51a4200c5431c5854840a78caedb309ce7kind, id, provider, clusterIdapiPreference, clusterId, dependsOn, deploymentTarget, id, kind, labels, provider, qdeviceNodeId, qdeviceState, qnetEndpoint, qnetHostIdentity, qnetHostKey, state
pvepveHostBackupsha256:5c15ff152d4596be75a783442608cc65100a3f3806d38b0b4ff7545415d2d278kind, id, provider, nodeId, sources, backupServer, accessPrincipal, pbsServer, pbsDatastore, pbsNamespace, pbsTokenId, pbsPasswordBinding, pbsServerCertificatePem, pbsTrustMode, schedule, maximumAge, stateaccessPrincipal, ageRecipients, ageRecipientsBinding, backupServer, dependsOn, deploymentTarget, id, kind, labels, maximumAge, nodeId, pbsDatastore, pbsFingerprint, pbsNamespace, pbsPasswordBinding, pbsServer, pbsServerCertificatePem, pbsTokenId, pbsTrustMode, provider, schedule, sources, state
pvepveHostStatesha256:47142ba7f1aa2d1c7d9e9ca80fd5363196ad776c1a2dbd73ecb1bc74bd354b42kind, id, provider, nodeId, hostname, bootMode, filesbootMode, captureDirectories, dependsOn, deploymentTarget, files, hostname, id, kind, labels, nodeId, provider, state
pvepveNodesha256:53acee0a63dd15d9ca1957d25320867d43bc18cd03163555d45c2962cc00644akind, id, provider, nodeId, proxmoxNodeName, cluster, addressaddress, cluster, defaultDiscoverySubnets, defaultDiskStorage, defaultGateway, defaultIsoStorage, defaultNetwork, dependsOn, deploymentTarget, id, kind, labels, nodeId, provider, proxmoxNodeName, state
pvepveNotificationMatchersha256:4bbea484840765c148c8e8be2b7cd4d85e99d3477f265f615fd0e0096c2f8e26kind, id, provider, matcherId, severities, targetsdependsOn, deploymentTarget, disableDefaultMatcher, id, kind, labels, matchMode, matcherId, provider, severities, state, targets
pvepveNotificationTargetsha256:f1a0168848cc8da50a1accf2926c5d5728472f4d3a0fb220bab469c515b4bbcfkind, id, provider, targetId, targetType, server, port, smtpMode, username, fromAddress, mailto, smtpSecretBindingauthor, dependsOn, deploymentTarget, fromAddress, id, kind, labels, mailto, port, provider, server, smtpMode, smtpSecretBinding, state, targetId, targetType, username
pvepveRolesha256:32fbeda88006826f0344772f95aa1326d066965aba38f2fbd1854d333f5122dfkind, id, provider, roleId, privilegesdependsOn, deploymentTarget, id, kind, labels, privileges, provider, roleId, state
pvestorageAttachmentsha256:e18768864307d886f6cbab72615018eff360881fad91db5294dbf37e3f55af31kind, id, provider, storageIdcontent, dependsOn, deploymentTarget, id, kind, labels, nodes, path, pbsDatastore, pbsFingerprint, pbsFingerprintBinding, pbsNamespace, pbsPasswordBinding, pbsServer, pbsUsername, provider, state, storageId, storageType
vmwarevmwareVmsha256:569d121c6d0346ce7b04781f6c76aa8a7adafc6f394da04b0b5005158b3303e3kind, id, provider, vmxPath, name, architecture, cores, memoryMiB, diskGiB, installerarchitecture, cores, dependsOn, deploymentTarget, diskGiB, id, installer, kind, labels, memoryMiB, name, provider, state, vmxPath
wslwslDistributionsha256:47407025f3757b41b12b41b25ccffb3f41849f7ae2a2845d58dd48a1c55c9f56kind, id, provider, windowsConnection, distribution, installRoot, archive, guestTransport, bootstrapUserarchive, bootstrapUser, dependsOn, deploymentTarget, distribution, guestHost, guestTransport, id, installRoot, kind, provider, state, windowsConnection, windowsPublicKey

Shared Nix option reference

Generated from nix/modules/authoring/. Do not edit by hand.

NamespacePurpose
nxd.siteTyped topology, lifecycle, identity, PVE, PBS, Headscale, recovery, notification, and retention declarations
nxd.providers.<kind>.<name>Linked-provider endpoint, credential binding, CA, dependencies, pinned arguments, and provider configuration
nxd.operations.<name>Explicit resource IDs or tags, lifecycle intent, and artifact-set selection
nxd.secrets.bindings.<name>One logical reference or one structured resolver/document/key reference
nxd.secrets.publicBindings.<name>A public whole-document or structured binding emitted as public/<name>

NXD derives canonical IDs, provider resources, associations, operation sets, and allowlisted PVE host-state files. It refuses duplicate IDs, unknown or unused reserved operation tags, unsupported host-state paths, and empty operation policy.

Compatibility matrix

See docs/compatibility.md in the repository source. Released manuals will include a generated compatibility matrix from release metadata.

Incident response

See docs/runbooks/incident-response.md in the repository source.

Do not include secrets, private endpoints, raw production journals, or unredacted infrastructure captures in public reports.

Release readiness

See docs/release/release-policy.md and docs/release/supply-chain.md.

NXD is pre-release. Release signing, SBOM, and provenance automation are planned pre-alpha work.

Security policy

See SECURITY.md in the repository root for current reporting instructions.

Common failures

Validation fails

Check for unknown fields, duplicate resource IDs, unresolved references, and invalid provider configuration.

Apply refuses a plan

Apply may refuse expired, stale, wrong-provider, incompatible, or changed-input plans. Re-run plan after investigating the refusal.

Provider operation is ambiguous

Mutation disconnects and timeouts are ambiguous. Do not blindly retry mutation. Observe current state and replan.

Contributing

Read CONTRIBUTING.md, AGENTS.md, and docs/README.md before proposing a change.

Non-trivial work requires accepted artifacts, tests, evidence, and review.