No description
  • Nix 98.5%
  • Shell 1.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
vnprc 826f409ec6 Template hypervisor wires allod bitcoin from the node's facts
hosts/hypervisor/nexus/home.nix sets nexus.bitcoinNode.facts and
.machines from hosts/privacy/bitcoin-node/facts.nix, so allod bitcoin
is on a fresh install's hypervisor. flake.nix wires it in as the
nexus definition's homeModules; README.md documents it.

Refs allod/profiles#14
2026-10-11 19:52:52 -04:00
checks Add privacy.bitcoin-node: a pruned, Tor-only node on a data disk 2026-10-11 18:20:46 -04:00
hooks Populate example machine profile definitions 2026-07-17 21:02:51 +00:00
hosts Template hypervisor wires allod bitcoin from the node's facts 2026-10-11 19:52:52 -04:00
modules Delete the forge SSH block and silence neovim provider warnings 2026-09-20 00:52:22 +00:00
.gitignore Populate example machine profile definitions 2026-07-17 21:02:51 +00:00
flake.lock flake.lock: update nixpkgs 2026-09-23 14:11:18 -04:00
flake.nix Template hypervisor wires allod bitcoin from the node's facts 2026-10-11 19:52:52 -04:00
LICENSE Add LICENSE (GPL-3.0-or-later) 2026-07-17 20:58:45 +00:00
pi-providers.json Add validated Pi provider catalog contract 2026-08-21 02:02:57 +00:00
README.md Template hypervisor wires allod bitcoin from the node's facts 2026-10-11 19:52:52 -04:00
setup.sh Populate example machine profile definitions 2026-07-17 21:02:51 +00:00

profiles

Allod example machine profile definitions — the single owner of which NixOS and Home Manager modules compose each machine, keyed by archetype. The archetypes framework composes these definitions with the vm/nexus framework modules plus inventory and secrets data to build machines.

This repo ships synthetic example definitions. A deploy flake redirects the framework's profiles input at an operator's own definitions repo — exporting this same contract — to describe real machines.

Ownership

This repo owns:

  • per-profile NixOS modules under hosts/<archetype>/<name>/configuration.nix
  • per-profile Home Manager modules under hosts/<archetype>/<name>/home.nix
  • shared profile Home Manager modules under modules/ (e.g. preferences.nix)
  • Pi provider endpoint, protocol, and model metadata in pi-providers.json
  • the profiles input contract: lib.profileDefinitions, the optional per-machine lib.profileData, lib.piProviders, lib.validatePiProviders, and homeModules.preferences

This repo does not own:

  • the archetype merge, builders, shared framework modules, vmFacts, and checks: archetypes
  • VM framework modules, disk layout, or base guest policy: vm
  • hypervisor framework modules and lifecycle scripts: nexus
  • machine inventory, VM specs, repository registry, IPs, MACs, and platforms: inventory
  • identity data, credential inventory, Forge hosts/users, token paths, and git policy data: secrets

Provider credentials, target machines, and recipient keys stay in secrets. The provider catalog never contains bearer values or machine selection.

The profiles input contract

flake.nix exports, as a literal attrset (no directory-derived magic):

lib.profileDefinitions = {
  <archetype> = {                 # dev | privacy | hypervisor | service
    <definition-name> = {
      override ? false;           # consumed only by the framework's compose layering
      nixosModules ? [ <module> ... ];
      homeModules  ? [ <module> ... ];
    };
  };
};
lib.profileData = {               # optional; absent machine keys are legal
  <machine-name> = { <builder-arg overrides> };
};
homeModules.preferences = <home-manager module>;

Archetype-name validity (dev/privacy/hypervisor/service) is asserted by the archetypes framework, the fact's owner — not here. This flake's own check validates only the structure and field types of its exports and needs no input beyond nixpkgs. It must never grow inputs on secrets or inventory: definitions reference behavior, not identity or machine facts.

Pi provider catalog

pi-providers.json is an object keyed by provider ID. The committed public catalog is empty. A private profiles input may populate it with provider metadata while preserving the same contract:

{
  "example-router": {
    "baseUrl": "https://router.example.invalid/v1",
    "api": "openai-responses",
    "models": [
      {
        "id": "example/model",
        "name": "Example model",
        "reasoning": true,
        "maxTokens": 32768
      }
    ]
  }
}

Validation is deliberately structural. Provider metadata is Pi's configuration format, and the framework's reconciler merges these objects into the agent's models.json verbatim, so Pi is what accepts or rejects an adapter name, a model field, or an endpoint it cannot reach — at the first request, with its own diagnostics. A closed-world schema here would mean every field Pi adds needs a change in this repo, a lock bump, and a rebuild before any deployment could use it, while buying nothing.

Three rules hold, and nothing else:

  • Provider IDs match ^[a-z0-9][a-z0-9-]*$. This is the join key between the catalog and the credential registry in secrets, and the key the reconciler's ownership manifest records, so a malformed one breaks the join rather than a request.
  • models is a non-empty array of objects, each with a non-empty string id. A provider Pi cannot route to is never a deliberate declaration.
  • baseUrl is a string beginning with https://. The credential a provider selects is a bearer token, so a plaintext scheme would put it on the wire. This is a property of the framework's credential handling, not of Pi's format.

Every other field — including adapter names and model fields this repo has never heard of — passes through unchanged. Provider api is optional and is defaulted to openai-completions when absent, the one value this repo supplies rather than checks.

Consumers read the normalized, validated catalog from lib.piProviders. Validation is attached to that exported value, so downstream composition fails closed even though a flake does not run its inputs' own checks. A profiles repo that replaces this input and holds its own catalog calls lib.validatePiProviders on its own data rather than copying the function.

Forge

service.forge (hosts/service/forge/configuration.nix) composes the framework's nixosModules.forgejo in fresh-install mode over plain http: a forge reachable only on its own guest network, with no TLS terminator and nothing to restore. That module does not arrive as a flake input — this repo takes only nixpkgs — so the definition receives it as allodModules.forgejo, an argument the service builder's specialArgs supplies at composition time.

sshPort = 2222 is the clone daemon; adminSshPort = 22 keeps administrative SSH on the port the hypervisor's provisioning already expects, since only one of the two may hold 22 and the module asserts they differ. domain becomes both ROOT_URL and the Caddy vhost's site address, so it must be a name or address something actually resolves to this guest — libvirt's dnsmasq does not resolve bare guest names, and this repo cannot hardcode the guest's address either, since getting-started.sh rewrites documentation addresses to the real subnet only in inventory and secrets. So domain comes from guestAddress, an argument the service builder's specialArgs supplies alongside allodModules; this repo carries no machine fact of its own. adminEmail has no such constraint — Forgejo only needs a syntactically valid sender address, nothing resolves it — so forge-admin@forge.invalid is a genuine placeholder a real deployment's definition replaces.

The module itself opens the ports it needs — the clone port, the http port, and, with tls = true, 443 — in networking.firewall.allowedTCPPorts once composed; the service archetype's own default egress opens nothing beyond administrative SSH, so this is the only layer that opens them. That composition, guestAddress included, cannot be evaluated from this repo: it needs allodModules.forgejo and guestAddress, both supplied by the service builder in archetypes, which does not carry this seam yet.

Bitcoin node

privacy.bitcoin-node (hosts/privacy/bitcoin-node/configuration.nix) is a pruned Bitcoin Core node: Tor-only by nftables topology after a one-time clearnet first sync, its chain state on a data disk, running stock pkgs.bitcoind from the cached binary — this profile never builds Bitcoin Core from source.

The template declares the machine itself: an inventory entry (bitcoin-node, 8 GB, 4 vCPUs, a 40 GB data-disk image under /var/lib/allod) and a secrets entry (the bitcoin account and a host-key slot the bootstrap script fills), so on a fresh install provision-vm bitcoin-node is the whole of it. A fork that will never host a node can leave it unprovisioned; a switch to take a template machine out of the build entirely is allod/strategy#67. Size the data disk from chainstate, the filter index, and blocks — never from the block count alone, since pruning and the filter index dominate the footprint.

hosts/privacy/bitcoin-node/facts.nix is the one file that names the data directory, the marker file, the service and timeout: the profile and the operator command (allod bitcoin, in allod/nexus) both read it, so a path or a unit name is never spelled twice. The template's hypervisor.nexus definition sets nexus.bitcoinNode.facts and nexus.bitcoinNode.machines from that same file (hosts/hypervisor/nexus/home.nix), so allod bitcoin status|start|stop|clearnet|cli is on the hypervisor of a fresh install.

Operate the node by hand on the guest as its own account, never as a login user: sudo -u bitcoind-main bitcoin-cli -datadir=/var/lib/bitcoin-node-data/bitcoind ... (bitcoin-cli looks in $HOME/.bitcoin, which does not exist under the account's home, so -datadir is required). allod bitcoin cli (allod/nexus) runs exactly that line over ssh.

Common commands

nix flake check                                        # validate the export shape
nix eval .#lib.profileDefinitions --json | jq 'keys'   # dev, hypervisor, privacy, service
nix eval .#lib.piProviders --json                      # normalized Pi providers
nix build .#checks.x86_64-linux.pi-provider-catalog   # schema + sabotage witness
nix build .#checks.x86_64-linux.bitcoin-node-machine  # the bitcoin-node NixOS VM test

Adding a profile definition

  1. Add the module files under hosts/<archetype>/<name>/.
  2. Add the definition to lib.profileDefinitions.<archetype>.<name> in flake.nix.
  3. Add the machine's facts in inventory and identity/credentials in secrets (separate repos).

History

This repo has fresh history. The example definitions and the preferences module were previously carried in the framework repo (allod/profiles, renamed to allod/archetypes) and the secrets template; the framework's pre-rename commits remain fetchable at the allod/archetypes URL.