diff --git a/.envrc.recommended b/.envrc.recommended
index 783a3af..bd6ffb8 100644
--- a/.envrc.recommended
+++ b/.envrc.recommended
@@ -1,4 +1,8 @@
 nix_direnv_manual_reload
 use flake
-export DATABASE_URL=postgresql://patagia:swordfish@/patagia?host=$XDG_RUNTIME_DIR/patagia-postgres
+export DATABASE_URL=postgresql://patagia:swordfish@patagia?host=$XDG_RUNTIME_DIR/patagia-postgres
+export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL="http/protobuf"
+export OTEL_RESOURCE_ATTRIBUTES=host.name=$HOSTNAME
+export OTEL_SERVICE_NAME=$USER.patagia-control
+export OTEL_TRACES_SAMPLER=always_on
 dotenv_if_exists
diff --git a/Cargo.lock b/Cargo.lock
index f4d53b1..3858c5b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1173,13 +1173,15 @@ dependencies = [
 
 [[package]]
 name = "instrumentation"
-version = "0.1.0"
+version = "0.2.0"
 dependencies = [
  "anyhow",
  "http",
  "once_cell",
  "opentelemetry",
+ "opentelemetry-appender-tracing",
  "opentelemetry-otlp",
+ "opentelemetry-resource-detectors",
  "opentelemetry-semantic-conventions",
  "opentelemetry_sdk",
  "tonic",
@@ -1508,6 +1510,20 @@ dependencies = [
  "tracing",
 ]
 
+[[package]]
+name = "opentelemetry-appender-tracing"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5feffc321035ad94088a7e5333abb4d84a8726e54a802e736ce9dd7237e85b"
+dependencies = [
+ "log",
+ "opentelemetry",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+ "tracing-subscriber",
+]
+
 [[package]]
 name = "opentelemetry-otlp"
 version = "0.27.0"
@@ -1539,6 +1555,17 @@ dependencies = [
  "tonic",
 ]
 
+[[package]]
+name = "opentelemetry-resource-detectors"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf6e83d3dca8fe93cfac95cd07313721c9e6e9f8655e7b06d061d4924df1a0cd"
+dependencies = [
+ "opentelemetry",
+ "opentelemetry-semantic-conventions",
+ "opentelemetry_sdk",
+]
+
 [[package]]
 name = "opentelemetry-semantic-conventions"
 version = "0.27.0"
@@ -1603,7 +1630,7 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
 [[package]]
 name = "patagia-agent"
-version = "0.1.0"
+version = "0.2.0"
 dependencies = [
  "anyhow",
  "clap",
@@ -1621,7 +1648,7 @@ dependencies = [
 
 [[package]]
 name = "patagia-controller"
-version = "0.1.0"
+version = "0.2.0"
 dependencies = [
  "anyhow",
  "clap",
@@ -2898,7 +2925,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
 
 [[package]]
 name = "trace-request"
-version = "0.1.0"
+version = "0.2.0"
 dependencies = [
  "dropshot",
  "http",
@@ -3505,7 +3532,7 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
 
 [[package]]
 name = "xtask"
-version = "0.0.0"
+version = "0.2.0"
 dependencies = [
  "anyhow",
  "clap",
diff --git a/Cargo.toml b/Cargo.toml
index 3acc508..6cf8849 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,18 +27,13 @@ anyhow = "1.0.95"
 clap = { version = "4.5.23", features = [
   "derive",
   "deprecated",
+  "env",
   "wrap_help",
   "string",
 ] }
 dropshot = "0.15.1"
 http = "1.2.0"
 once_cell = "1.20.2"
-opentelemetry = "0.27.1"
-opentelemetry-appender-tracing = { version = "0.27.0", features = ["log", "experimental_metadata_attributes"] }
-opentelemetry-otlp = { version = "0.27.0", features = ["grpc-tonic", "gzip-tonic", "zstd-tonic", "tls", "tls-roots", "trace"] }
-opentelemetry_sdk = { version = "0.27.1", features = ["metrics", "rt-tokio"] }
-opentelemetry-semantic-conventions = "0.27.0"
-opentelemetry-stdout = "0.27.0"
 progenitor = "0.8.0"
 reqwest = { version = "0.12.12", features = ["json", "stream", "rustls-tls"] }
 schemars = "0.8.21"
@@ -47,16 +42,8 @@ serde = { version = "1.0.217", features = ["derive"] }
 slog = "2.7.0"
 slog-async = "2.8.0"
 tokio = { version = "1.42.0", features = ["full"] }
-tonic = "0.12.3"
 tracing = "0.1.41"
 tracing-core = "0.1.33"
 tracing-chrome = "0.7.2"
-tracing-opentelemetry = "0.28.0"
 tracing-slog = { git = "https://github.com/oxidecomputer/tracing-slog", default-features = false }
-tracing-subscriber = { version = "0.3.19", default-features = false, features = [
-  "std",
-  "ansi",
-  "env-filter",
-  "fmt",
-] }
 uuid = { version = "1", features = [ "serde", "v4" ] }
diff --git a/agent/Cargo.toml b/agent/Cargo.toml
index ebacdfd..d8d25f0 100644
--- a/agent/Cargo.toml
+++ b/agent/Cargo.toml
@@ -1,8 +1,8 @@
 [package]
 name = "patagia-agent"
-version = "0.1.0"
 edition = "2021"
 license = "MPL-2.0"
+version.workspace = true
 
 [dependencies]
 anyhow.workspace = true
diff --git a/agent/src/io_systemd_Hostname.rs b/agent/src/io_systemd_Hostname.rs
index 812f168..e9fa185 100644
--- a/agent/src/io_systemd_Hostname.rs
+++ b/agent/src/io_systemd_Hostname.rs
@@ -163,7 +163,6 @@ pub struct Describe_Reply {
 impl varlink::VarlinkReply for Describe_Reply {}
 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
 pub struct Describe_Args {}
-#[allow(dead_code)]
 pub trait Call_Describe: VarlinkCallError {
     fn reply(
         &mut self,
diff --git a/agent/src/main.rs b/agent/src/main.rs
index 34ee7f7..60c177a 100644
--- a/agent/src/main.rs
+++ b/agent/src/main.rs
@@ -1,11 +1,11 @@
+use crate::io_systemd_Hostname::VarlinkClientInterface;
 use anyhow::Result;
 use clap::Parser;
 use tokio::time::{sleep, Duration};
 use varlink::Connection;
-use io_systemd_Hostname::VarlinkClientInterface;
 
-mod patagia_api;
 mod io_systemd_Hostname;
+mod patagia_api;
 
 #[derive(Parser, Debug)]
 #[command(version, about, long_about = None)]
@@ -37,11 +37,15 @@ async fn main() -> Result<()> {
     let mut systemd_hostname_iface = io_systemd_Hostname::VarlinkClient::new(conn);
 
     let desc = systemd_hostname_iface.describe().call()?;
-    println!("Welcome {} (Machine ID: {})!", desc.Hostname, desc.MachineID);
+    println!(
+        "Welcome {} (Machine ID: {})!",
+        desc.Hostname, desc.MachineID
+    );
 
     let client = patagia_api::Client::new("http://localhost:9474");
     let result = client.version().await?;
     tracing::info!("Result: {:?}", result);
+    tracing::info!("Patagia Agent finished");
 
     sleep(Duration::from_secs(3)).await;
     Ok(())
diff --git a/controller/Cargo.toml b/controller/Cargo.toml
index 629468d..baa4054 100644
--- a/controller/Cargo.toml
+++ b/controller/Cargo.toml
@@ -1,9 +1,9 @@
 [package]
 name = "patagia-controller"
-description = "Patagia controller server"
-version = "0.1.0"
+description = "Patagia control plane server"
 edition = "2021"
 license = "MPL-2.0"
+version.workspace = true
 
 [dependencies]
 anyhow.workspace = true
diff --git a/controller/src/bin/patagia-controller.rs b/controller/src/bin/patagia-controller.rs
index 7c43aa5..845cfd6 100644
--- a/controller/src/bin/patagia-controller.rs
+++ b/controller/src/bin/patagia-controller.rs
@@ -18,7 +18,7 @@ struct Cli {
     #[arg(
         long = "telemetry-otlp-endpoint",
         default_value = "http://localhost:4317",
-        value_name = "OTEL_EXPORTER_OTLP_ENDPOINT"
+        env = "OTEL_EXPORTER_OTLP_ENDPOINT"
     )]
     otlp_endpoint: Option<String>,
 
@@ -26,9 +26,16 @@ struct Cli {
         long = "log-stderr",
         short = 'v',
         default_value = "false",
-        value_name = "LOG_TO_STDERR"
+        env = "LOG_TO_STDERR"
     )]
     log_stderr: bool,
+
+    #[arg(
+        long = "listen-address",
+        default_value = "0.0.0.0:9474",
+        env = "LISTEN_ADDRESS"
+    )]
+    listen_address: String,
 }
 
 #[tokio::main]
@@ -39,7 +46,7 @@ async fn main() -> Result<()> {
     tracing::info!("Patagia Controller");
 
     let config = ConfigDropshot {
-        bind_address: SocketAddr::from_str("0.0.0.0:9474").unwrap(),
+        bind_address: SocketAddr::from_str(&args.listen_address).unwrap(),
         ..Default::default()
     };
 
diff --git a/instrumentation/Cargo.toml b/instrumentation/Cargo.toml
index 57edfd5..aeb8843 100644
--- a/instrumentation/Cargo.toml
+++ b/instrumentation/Cargo.toml
@@ -1,17 +1,24 @@
 [package]
 name = "instrumentation"
-version = "0.1.0"
 edition = "2021"
 license = "MPL-2.0"
+version.workspace = true
 
 [dependencies]
 anyhow.workspace = true
 http.workspace = true
 once_cell.workspace = true
-opentelemetry-otlp.workspace = true
-opentelemetry_sdk.workspace = true
-opentelemetry-semantic-conventions.workspace = true
-opentelemetry.workspace = true
-tonic.workspace = true
-tracing-opentelemetry.workspace = true
-tracing-subscriber.workspace = true
+opentelemetry-otlp = { version = "0.27.0", features = ["grpc-tonic", "gzip-tonic", "zstd-tonic", "tls", "tls-roots", "trace"] }
+opentelemetry_sdk = { version = "0.27.1", features = ["metrics", "rt-tokio"] }
+opentelemetry-semantic-conventions = "0.27.0"
+opentelemetry-appender-tracing = { version = "0.27.0", features = ["log", "experimental_metadata_attributes"] }
+opentelemetry-resource-detectors = { version = "0.6.0" }
+opentelemetry = "0.27.1"
+tonic = "0.12.3"
+tracing-opentelemetry = "0.28.0"
+tracing-subscriber = { version = "0.3.19", default-features = false, features = [
+  "std",
+  "ansi",
+  "env-filter",
+  "fmt",
+] }
diff --git a/instrumentation/src/lib.rs b/instrumentation/src/lib.rs
index 62bfa08..31df7f6 100644
--- a/instrumentation/src/lib.rs
+++ b/instrumentation/src/lib.rs
@@ -1,5 +1,4 @@
 use anyhow::{anyhow, Result};
-use once_cell::sync::Lazy;
 use opentelemetry::{trace::TracerProvider as _, KeyValue};
 use opentelemetry_otlp::{WithExportConfig, WithTonicConfig};
 use opentelemetry_sdk::{
@@ -9,25 +8,15 @@ use opentelemetry_sdk::{
     trace::{RandomIdGenerator, Sampler, TracerProvider},
     Resource,
 };
+use opentelemetry_semantic_conventions as semcov;
 use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
 use tracing_subscriber::layer::SubscriberExt;
 use tracing_subscriber::util::SubscriberInitExt;
 
-static RESOURCE: Lazy<Resource> = Lazy::new(|| {
-    Resource::new(vec![
-        KeyValue::new(
-            opentelemetry_semantic_conventions::resource::SERVICE_NAME,
-            env!("CARGO_PKG_NAME"),
-        ),
-        KeyValue::new(
-            opentelemetry_semantic_conventions::resource::SERVICE_VERSION,
-            env!("CARGO_PKG_VERSION"),
-        ),
-    ])
-});
+use std::time::Duration;
 
 // Construct MeterProvider for MetricsLayer
-fn init_meter_provider(otel_endpoint: &String) -> Result<SdkMeterProvider> {
+fn init_meter_provider(otel_endpoint: &String, resource: Resource) -> Result<SdkMeterProvider> {
     let exporter = opentelemetry_otlp::MetricExporter::builder()
         .with_tonic()
         .with_endpoint(otel_endpoint)
@@ -38,7 +27,7 @@ fn init_meter_provider(otel_endpoint: &String) -> Result<SdkMeterProvider> {
         .map_err(|e| anyhow!("Error creating OTLP metric exporter: {:?}", e))?;
 
     let meter_provider = MeterProviderBuilder::default()
-        .with_resource(RESOURCE.clone())
+        .with_resource(resource)
         .with_reader(
             PeriodicReader::builder(exporter, runtime::Tokio)
                 .with_interval(std::time::Duration::from_secs(10))
@@ -52,7 +41,7 @@ fn init_meter_provider(otel_endpoint: &String) -> Result<SdkMeterProvider> {
 }
 
 // Construct TracerProvider for OpenTelemetryLayer
-fn init_tracer_provider(otel_endpoint: &String) -> Result<TracerProvider> {
+fn init_tracer_provider(otel_endpoint: &String, resource: Resource) -> Result<TracerProvider> {
     let exporter = opentelemetry_otlp::SpanExporter::builder()
         .with_tonic()
         .with_tls_config(tonic::transport::ClientTlsConfig::new().with_native_roots())
@@ -65,7 +54,7 @@ fn init_tracer_provider(otel_endpoint: &String) -> Result<TracerProvider> {
         .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
             1.0,
         ))))
-        .with_resource(RESOURCE.clone())
+        .with_resource(resource)
         .with_id_generator(RandomIdGenerator::default())
         .with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio)
         .build();
@@ -75,6 +64,25 @@ fn init_tracer_provider(otel_endpoint: &String) -> Result<TracerProvider> {
 
 // Initialize tracing-subscriber and return TracingGuard for opentelemetry-related termination processing
 pub fn init_tracing(otel_endpoint: Option<&String>, log_stderr: bool) -> Result<TracingGuard> {
+    let resource = {
+        let r = Resource::new([KeyValue::new(
+            semcov::resource::SERVICE_VERSION,
+            env!("CARGO_PKG_VERSION"),
+        )]);
+
+        let detected = Resource::from_detectors(
+            Duration::from_secs(5),
+            vec![
+                Box::new(opentelemetry_sdk::resource::SdkProvidedResourceDetector),
+                Box::new(opentelemetry_sdk::resource::EnvResourceDetector::new()),
+                Box::new(opentelemetry_resource_detectors::OsResourceDetector),
+                Box::new(opentelemetry_resource_detectors::ProcessResourceDetector),
+                Box::new(opentelemetry_sdk::resource::TelemetryResourceDetector),
+            ],
+        );
+        r.merge(&detected)
+    };
+
     let env_filter = tracing_subscriber::EnvFilter::try_from_default_env()
         .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(""));
 
@@ -84,7 +92,7 @@ pub fn init_tracing(otel_endpoint: Option<&String>, log_stderr: bool) -> Result<
     };
 
     let meter_provider = match otel_endpoint {
-        Some(endpoint) => Some(init_meter_provider(endpoint)?),
+        Some(endpoint) => Some(init_meter_provider(endpoint, resource.clone())?),
         None => None,
     };
 
@@ -94,7 +102,7 @@ pub fn init_tracing(otel_endpoint: Option<&String>, log_stderr: bool) -> Result<
     };
 
     let tracer_provider = match otel_endpoint {
-        Some(endpoint) => Some(init_tracer_provider(endpoint)?),
+        Some(endpoint) => Some(init_tracer_provider(endpoint, resource)?),
         None => None,
     };
 
diff --git a/justfile b/justfile
index 059915e..f7b69d7 100644
--- a/justfile
+++ b/justfile
@@ -57,7 +57,7 @@ check-nix:
 
 # Run PostgreSQL for development and testing
 dev-postgres:
-  mkdir -p "$XDG_RUNTIME_DIR/patagia-postgres"
+  mkdir -p "${XDG_RUNTIME_DIR}/patagia-postgres"
   podman volume exists patagia-postgres || podman volume create patagia-postgres
   podman run \
   --detach \
@@ -67,12 +67,9 @@ dev-postgres:
   --env POSTGRES_USER=patagia \
   --env POSTGRES_PASSWORD=swordfish \
   --volume patagia-postgres:/var/lib/postgresql/data \
-  --volume "$XDG_RUNTIME_DIR/patagia-postgres:/var/run/postgresql" \
+  --volume "${XDG_RUNTIME_DIR}/patagia-postgres:/var/run/postgresql" \
   docker.io/postgres:17
 
-# Reset PostgreSQL data and start
-dev-postgres-reset: dev-postgres-clean dev-postgres
-
 # Clean up PostgreSQL data
 dev-postgres-clean:
   podman rm -f patagia-postgres || true
diff --git a/trace-request/Cargo.toml b/trace-request/Cargo.toml
index 24de8bd..87e773c 100644
--- a/trace-request/Cargo.toml
+++ b/trace-request/Cargo.toml
@@ -1,8 +1,8 @@
 [package]
 name = "trace-request"
-version = "0.1.0"
 edition = "2021"
 license = "MPL-2.0"
+version.workspace = true
 
 [lib]
 proc-macro = true
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index 848c00e..4df5ed7 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "xtask"
-version = "0.0.0"
 edition = "2021"
+version.workspace = true
 
 [[bin]]
 name = "xtask"