Infrastructure as one reconciled graph.
DECLARE · RECONCILE · PROVE
ifx plans cloud resources, local virtual machines, host configuration, and the checks
that prove the result as one dependency graph. A reference such as vm.connection()
carries both a value and an ordering edge: create the VM before configuring it, and
delete it after its files, packages, and services.
Rust is the production stack language. The lightweight ifx-program crate supplies generated,
typed builders. ifxd watches and compiles configured stack roots, emits immutable
Program revisions, validates them, and owns every provider operation. The ifx CLI is a
control-plane client; it never executes a stack or provider locally.
The experimental IFX DSL and LSP now provide fluent declarations,
typed local modules and ordered configuration lambdas. ifx-lang checks/compiles
them locally and tests configuration against an in-memory host; real host execution
and integration into burn remain separate work. The
edition 0.2 authoring MVP adds functions, structs,
constructors, explicit returns, TOML root inputs and cross-file editor navigation.
Its application, fleet and lifecycle examples are executable offline.
| Declare | Reconcile | Prove |
|---|---|---|
| Write a typed Rust program. | Observe providers and hosts, then apply one graph-ordered diff. | Put checks in the graph and inspect build, health, drift, and run history through ifxd. |
Build the client, daemon, and Rust lab runner:
$ cargo build -p ifx-cli -p ifxd -p ifx-labs
$ cargo run -p ifx-labs -- run 1Lab 1 needs no account or root access. The runner starts an isolated daemon, waits for its background compiler, applies the stack, proves idempotence, and destroys it.
The primary local integration target is Lab 8. It downloads and verifies one Debian cloud image, creates three qcow2 overlays, joins the guests as a two-link router → middle → leaf chain, removes transitional direct SSH access, configures nginx through the final nested SSH paths, checks host-to-guest and guest-to-guest traffic, then tears the guests down while retaining the verified image cache:
$ cargo run -p ifx-labs -- run 8QEMU, qemu-img, ssh-keygen, and either cloud-localds, genisoimage, or xorriso
are required. KVM is used when available; otherwise the provider falls back to TCG.
The preview is narrated at human pace. Click it for the asciinema cast.
The schema is the source of truth for these builders, input types, defaults, replacement rules, sensitive fields, and typed outputs.
use std::process::ExitCode;
use ifx_program::host;
use ifx_program::emit_program;
const DEFAULT_IMAGE_URL: &str =
"https://cloud.debian.org/images/cloud/trixie/example/debian.qcow2";
const DEFAULT_IMAGE_SHA256: &str = "replace-with-the-pinned-sha256";
fn main() -> ExitCode {
emit_program(|stack, context| {
let root: String = context.config("lab_dir")?;
let image_url: String = context
.config_optional("image_url")?
.unwrap_or_else(|| DEFAULT_IMAGE_URL.to_string());
let image_sha256: String = context
.config_optional("image_sha256")?
.unwrap_or_else(|| DEFAULT_IMAGE_SHA256.to_string());
let image = stack
.qemu_image("debian")
.url(image_url)
.sha256(image_sha256)
.dir(&root)
.add()?;
let lan = stack
.qemu_network("lan")
.name("demo")
.dir(&root)
.add()?;
let vm = stack
.qemu_instance("web")
.dir(&root)
.image(image.path())
.networks([lan.endpoint()])
.add()?;
let packages = stack
.host_package("nginx")
.on(vm.connection())
.names(["nginx"])
.add()?;
let page = stack
.host_file("page")
.on(vm.connection())
.path("/var/www/html/index.html")
.content("<h1>hello from ifx</h1>\n")
.privileged(true)
.depends_on(&packages)
.add()?;
stack
.host_service("nginx")
.on(vm.connection())
.name("nginx")
.enabled(true)
.state(host::ServiceState::Running)
.triggered_by(&page)
.add()?;
Ok(())
})
}A standalone stack contains Cargo.toml, Cargo.lock, src/main.rs, and ifx.toml.
ifxd must explicitly configure its directory as a trusted authoring root:
# ifx.toml
name = "demo"
file = "Cargo.toml"
[config]
lab_dir = "/tmp/ifx-demo"$ ifxd --db surrealkv://$PWD/.ifx/db --stack "$PWD=default" &
$ ifx build
$ ifx plan
$ ifx apply -y
$ ifx graph --format html --out deployment.html
$ ifx status
$ ifx destroy -yifx build manually retries immediately. Ordinarily the daemon notices stack, local
path dependency, workspace/lock, Cargo configuration, toolchain, and ifx.toml edits
every 250 ms and builds in the background. Each event—or scan failure—marks the previous
Program stale before compilation starts. Plan, apply, refresh, drift, and graph
resolution fail closed until the current generation is ready; health checks may
continue against deployed state.
Open http://127.0.0.1:7433/ for the live graph, or export a self-contained document:
$ ifx graph --format html --out deployment.htmlThe Explorer shows desired and observed properties, reference/dependency/trigger edges, pending actions, health, durable runs, source generation, build duration, diagnostics, and revision freshness. Layouts shape the same graph by build dependency, declared resource utilization, logical/physical layer, human/computer-facing surface, provider, health, or lifecycle action.
| Types | Purpose |
|---|---|
qemu.image, qemu.volume, qemu.network, qemu.instance |
Verified images, durable disks, rootless networks, and local VMs |
linode.instance, linode.firewall, linode.domain, linode.domain_record |
Linode compute, firewall, and DNS resources |
host.file, host.package, host.service, host.exec, host.user |
Local or SSH host configuration |
check.http, check.tcp, check.exec |
Apply-time and continuously monitored checks |
memory.value |
Small stateful resource used by examples and tests |
Run ifx schema for installed types or read the generated
resource reference.
ifxdis the compiler, execution, persistence, retry, approval, and observation boundary.- Only administrator-configured local stack roots are compiled; clients cannot upload source paths or submit arbitrary Program revisions.
- Compiled emitters are configuration-independent. Configuration-only runs emit a new content-addressed Program without invoking Cargo.
- All stacks share one locked, garbage-collected Cargo target cache. It defaults to
$XDG_CACHE_HOME/ifx/rustor~/.cache/ifx/rustand can be moved withIFX_CACHE_DIR; stable runtime copies live under each stack's.ifx/build. - Program revisions, state, execution events, approvals, recovery journals, health, and drift history are stored through the daemon's SurrealDB-backed store.
- Manual retry wakes execution backoff immediately; unattended retries retain capped exponential backoff.
| Guide | Purpose |
|---|---|
| Getting started | Build, run, and understand the first stack |
| Labs | Executable, narrated learning sequence |
| Rust stack authoring | Builders, configuration, references, components, and iteration |
| CLI | Commands, configuration, exit codes, and state operations |
ifxd |
Continuous builds, revisions, runs, security, and API |
| Daemon brokering | Scoped lifecycle delegation without sharing upstream credentials |
| QEMU | Images, volumes, networks, instances, lifecycle, and prerequisites |
| Linode | Compute, firewall, DNS, and lifecycle coverage |
| Provider authoring | Handler lifecycle, schemas, generation, and tests |
| Design | Graph, compilation, reconciliation, and persistence model |
| Troubleshooting | Build, daemon, SSH, QEMU, state, and database failures |
| Performance | Cold/warm/edit, stack-size, QEMU, cache, and binary measurements |
The documentation website is in website/. It is dark-mode only
and syncs these Markdown sources into the published handbook.
$ cargo fmt --all --check
$ cargo clippy --workspace --all-targets --locked -- -D warnings
$ cargo run -p ifx-gen --locked -- --check
$ cargo test --workspace --locked
$ cargo run -p ifx-labs -- docsAll standalone labs and examples are checked with their committed lockfiles. The repository contains no alternate stack runtime or language-specific package.
Licensed under Apache-2.0 or MIT.


