Third Score companion (after AgentObservation and SmokeTest), per
ADR-023 P7 — new framework capabilities attach as companions rather
than as additions to the Score / Interpret public API. Powers the
dashboard's "View logs" UX: customer clicks the button, gets the last
N lines of a deployment's container output from the device.
Trait + transport-side impl + unit tests ship now. The agent-side
Verb::Logs handler and the operator dashboard handler land in
follow-up PRs against the contract locked here — splitting keeps each
diff focused and reviewable.
Three small types + a NATS-backed impl, zero edits to Score /
Interpret / Maestro:
LogChunk pure value: source identifier, captured_at, lines
(oldest-first), truncated flag. No transport,
no async, no IO — the dashboard renders it,
the transport layer constructs it.
LogQueryError six arms, each mapped to a distinct operator
action (DeviceOffline vs Timeout vs Agent vs
BadReply vs Transport vs InvalidReply). Mirrors
the FleetCommandsClient::CommandError shape used
by Verb::Ping so callers see uniform error
surfaces across verbs.
LogQuery<T> companion trait paired with a Score by associated
type — Q: LogQuery<T, Score = S> is the same
compile-time lock SmokeTest uses. A future
K8sLogQuery follows the same shape, no
Box<dyn LogQuery> needed (topologies are
compile-time per ADR-023 P6).
PodmanLogQuery NATS request/reply impl targeting
device-commands.<id>.logs. Splits routing
(LogQueryRouting) from transport so unit tests
verify the exact wire bytes without a NATS
client. Saturates LogsRequest.lines at
LOGS_MAX_LINES on the operator side as
defense-in-depth (the agent will clamp again).
reconciler-contracts gains Verb::Logs, LogsRequest, LogsReply, and
the LOGS_MAX_LINES bound. The wire shape lives there (not in the
deploy crate) so the agent build — which must not depend on harmony
— can serialize the same bytes. Adding the verb required zero
permission template changes: the agent's existing
device-commands.<id>.> subscription already covers it, and the
verb stays the trailing subject token so Verb::as_subject_token
keeps its invariant.
Tests assert behavior, not shape: subject_matches_documented_format
locks the wire so a callout permission change can't silently break
routing, request_body_clamps_oversized_n proves the
buggy-dashboard-show-all-button can't get through unchecked,
decode_reply_rejects_invalid_source_name proves a malicious agent
can't smuggle control characters past ProbeName validation, and
paired_score_type_is_podman_v0_score is a compile-time check that
catches refactors changing the associated type without updating
callers. 77 unit tests total across both crates, all passing without
requiring a real podman socket or NATS server.
Deferred (in scope of v0.3, separate PRs):
- Agent-side Verb::Logs handler in command_server.rs (parses
LogsRequest, resolves deployment->container with stricter
[a-zA-Z0-9_.-]{1,128} validation, runs podman logs --tail,
serializes LogsReply).
- Operator dashboard handler at
/deployments/<name>/devices/<id>/logs.
- End-to-end integration test through a real podman container.
Harmony
Infrastructure orchestration that treats your platform like first-class code.
Harmony is an open-source framework that brings the rigor of software engineering to infrastructure management. Write Rust code to define what you want, and Harmony handles the rest — from local development to production clusters.
By NationTech
The Problem Harmony Solves
Modern infrastructure is messy. Your Kubernetes cluster needs monitoring. Your bare-metal servers need provisioning. Your applications need deployments. Each comes with its own tooling, its own configuration format, and its own failure modes.
What if you could describe your entire platform in one consistent language?
That's Harmony. It unifies project scaffolding, infrastructure provisioning, application deployment, and day-2 operations into a single strongly-typed Rust codebase.
Three Principles That Make the Difference
| Principle | What It Means |
|---|---|
| Infrastructure as Resilient Code | Stop fighting with YAML and bash. Write type-safe Rust that you can test, version, and refactor like any other code. |
| Prove It Works Before You Deploy | Harmony verifies at compile time that your application can actually run on your target infrastructure. No more "the config looks right but it doesn't work" surprises. |
| One Unified Model | Software and infrastructure are one system. Deploy from laptop to production cluster without switching contexts or tools. |
How It Works: The Core Concepts
Harmony is built around three concepts that work together:
Score — "What You Want"
A Score is a declarative description of desired state. Think of it as a "recipe" that says what you want without specifying how to get there.
// "I want a PostgreSQL cluster running with default settings"
let postgres = PostgreSQLScore {
config: PostgreSQLConfig {
cluster_name: "harmony-postgres-example".to_string(),
namespace: "harmony-postgres-example".to_string(),
..Default::default()
},
};
Topology — "Where It Goes"
A Topology represents your infrastructure environment and its capabilities. It answers the question: "What can this environment actually do?"
// Deploy to a local K3D cluster, or any Kubernetes cluster via environment variables
K8sAnywhereTopology::from_env()
Interpret — "How It Happens"
An Interpret is the execution logic that connects your Score to your Topology. It translates "what you want" into "what the infrastructure does."
The Compile-Time Check: Before your code ever runs, Harmony verifies that your Score is compatible with your Topology. If your application needs a feature your infrastructure doesn't provide, you get a compile error — not a runtime failure.
What You Can Deploy
Harmony ships with ready-made Scores for:
Data Services
- PostgreSQL clusters (via CloudNativePG operator)
- Multi-site PostgreSQL with failover
Kubernetes
- Namespaces, Deployments, Ingress
- Helm charts
- cert-manager for TLS
- Monitoring (Prometheus, alerting, ntfy)
Bare Metal / Infrastructure
- OKD clusters from scratch
- OPNsense firewalls
- Network services (DNS, DHCP, TFTP)
- Brocade switch configuration
And more: Application deployment, tenant management, load balancing, and more.
Quick Start: Deploy a PostgreSQL Cluster
This example provisions a local Kubernetes cluster (K3D) and deploys a PostgreSQL cluster on it — no external infrastructure required.
use harmony::{
inventory::Inventory,
modules::postgresql::{PostgreSQLScore, capability::PostgreSQLConfig},
topology::K8sAnywhereTopology,
};
#[tokio::main]
async fn main() {
let postgres = PostgreSQLScore {
config: PostgreSQLConfig {
cluster_name: "harmony-postgres-example".to_string(),
namespace: "harmony-postgres-example".to_string(),
..Default::default()
},
};
harmony_cli::run(
Inventory::autoload(),
K8sAnywhereTopology::from_env(),
vec![Box::new(postgres)],
None,
)
.await
.unwrap();
}
What this actually does
When you compile and run this program:
- Compiles the Harmony Score into an executable
- Connects to
K8sAnywhereTopology— which auto-provisions a local K3D cluster if none exists - Installs the CloudNativePG operator into the cluster (one-time setup)
- Creates a PostgreSQL cluster with 1 instance and 1 GiB of storage
- Exposes the PostgreSQL instance as a Kubernetes Service
Prerequisites
- Rust (edition 2024)
- Docker (for the local K3D cluster)
- kubectl (optional, for inspecting the cluster)
Run it
# Clone the repository
git clone https://git.nationtech.io/nationtech/harmony
cd harmony
# Build the project
cargo build --release
# Run the example
cargo run -p example-postgresql
Harmony will print its progress as it sets up the cluster and deploys PostgreSQL. When complete, you can inspect the deployment:
kubectl get pods -n harmony-postgres-example
kubectl get secret -n harmony-postgres-example harmony-postgres-example-db-user -o jsonpath='{.data.password}' | base64 -d
To connect to the database, forward the port:
kubectl port-forward -n harmony-postgres-example svc/harmony-postgres-example-rw 5432:5432
psql -h localhost -p 5432 -U postgres
To clean up, delete the K3D cluster:
k3d cluster delete harmony-postgres-example
Environment Variables
K8sAnywhereTopology::from_env() reads the following environment variables to determine where and how to connect:
| Variable | Default | Description |
|---|---|---|
KUBECONFIG |
~/.kube/config |
Path to your kubeconfig file |
HARMONY_AUTOINSTALL |
true |
Auto-provision a local K3D cluster if none found |
HARMONY_USE_LOCAL_K3D |
true |
Always prefer local K3D over remote clusters |
HARMONY_PROFILE |
dev |
Deployment profile: dev, staging, or prod |
HARMONY_K8S_CONTEXT |
none | Use a specific kubeconfig context |
HARMONY_PUBLIC_DOMAIN |
none | Public domain for ingress endpoints |
To connect to an existing Kubernetes cluster instead of provisioning K3D:
# Point to your kubeconfig
export KUBECONFIG=/path/to/your/kubeconfig
export HARMONY_USE_LOCAL_K3D=false
export HARMONY_AUTOINSTALL=false
# Then run
cargo run -p example-postgresql
Documentation
| I want to... | Start here |
|---|---|
| Understand the core concepts | Core Concepts |
| Deploy my first application | Getting Started Guide |
| Explore available components | Scores Catalog · Topologies Catalog |
| See a complete bare-metal deployment | OKD on Bare Metal |
| Build my own Score or Topology | Developer Guide |
Why Rust?
We chose Rust for the same reason you might: reliability through type safety.
Infrastructure code runs in production. It needs to be correct. Rust's ownership model and type system let us build a framework where:
- Invalid configurations fail at compile time, not at 3 AM
- Refactoring infrastructure is as safe as refactoring application code
- The compiler verifies that your platform can actually fulfill your requirements
See ADR-001 · Why Rust for our full rationale.
Architecture Decisions
Harmony's design is documented through Architecture Decision Records (ADRs):
- ADR-001 · Why Rust
- ADR-003 · Infrastructure Abstractions
- ADR-006 · Secret Management
- ADR-011 · Multi-Tenant Cluster
License
Harmony is released under the GNU AGPL v3.
We choose a strong copyleft license to ensure the project—and every improvement to it—remains open and benefits the entire community.
See LICENSE for the full text.
Made with ❤️ & 🦀 by NationTech and the Harmony community