- Nix 98.5%
- Shell 1.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
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 |
||
| checks | ||
| hooks | ||
| hosts | ||
| modules | ||
| .gitignore | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| pi-providers.json | ||
| README.md | ||
| setup.sh | ||
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
profilesinput contract:lib.profileDefinitions, the optional per-machinelib.profileData,lib.piProviders,lib.validatePiProviders, andhomeModules.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 insecrets, and the key the reconciler's ownership manifest records, so a malformed one breaks the join rather than a request. modelsis a non-empty array of objects, each with a non-empty stringid. A provider Pi cannot route to is never a deliberate declaration.baseUrlis a string beginning withhttps://. 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
- Add the module files under
hosts/<archetype>/<name>/. - Add the definition to
lib.profileDefinitions.<archetype>.<name>inflake.nix. - Add the machine's facts in
inventoryand identity/credentials insecrets(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.