diff --git a/Cargo.toml b/Cargo.toml
index 692d90069e4aed5316eb66edc68cf731ae8b846f..78ba00ceae0c53cd137229f65ab659808c2791d9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,6 +30,7 @@ serde_json = { version = "1.0.127", features = ["preserve_order"] }
 color-print = { git = "https://gitlab.com/iago-lito/color-print", branch = "dev", version = "0.3.6" }
 color-print-proc-macro = { git = "https://gitlab.com/iago-lito/color-print", branch = "dev", version = "0.3.6" }
 csv = "1.3.0"
+pathdiff = "0.2.1"
 
 [dev-dependencies]
 rand = "0.8.5"
diff --git a/src/bin/aphid/main.rs b/src/bin/aphid/main.rs
index 3ad4f38d32170c1d9910968c443c238772b8a595..d03727778af5d2a8e2eb118fb6c792a8643fc4ad 100644
--- a/src/bin/aphid/main.rs
+++ b/src/bin/aphid/main.rs
@@ -3,12 +3,14 @@ use std::{
     fs::{self, File},
     io::Write as IoWrite,
     path::{self, Path, PathBuf},
-    process, time::Instant,
+    process,
+    time::Instant,
 };
 
 use aphid::{
     extract_local_triplet, imbalance,
     interner::{Interner, ResolvedSymbol, SpeciesSymbol},
+    io::ToRelative,
     it_mean::SummedMean,
     ln_likelihood, optimize_likelihood,
     output::{self, detail, file},
@@ -98,8 +100,12 @@ fn run() -> Result<(), Error> {
     Ok(())
 }
 
-fn read_inputs(args: &args::Args, output_folder: &Path, interner: &mut Interner) -> Result<(Config, GenesForest), Error> {
-    let path = &args.config;
+fn read_inputs(
+    args: &args::Args,
+    output_folder: &Path,
+    interner: &mut Interner,
+) -> Result<(Config, GenesForest), Error> {
+    let path = &args.config.canonicalize()?;
     cprintln!("Read config from <b>{}</>.", path.display());
     let config = Config::from_file(path, output_folder, interner)?;
 
@@ -151,23 +157,26 @@ fn prepare_output(output: &Path, args: &args::Args) -> Result<(), Error> {
     match (output.exists(), args.force) {
         (true, true) => {
             cprintln!(
-                "  <y>Removing</> existing folder: <b>{}</>.",
+                "  <y>Replacing</> existing folder: <b>{}</>.",
                 output.display()
             );
-            fs::remove_dir_all(&output)?;
+            fs::remove_dir_all(output)?;
         }
         (true, false) => OutputExistsErr { path: &output }.fail()?,
         (false, _) => {
             cprintln!("  Creating empty folder: <b>{}</>.", output.display());
         }
     };
-    fs::create_dir_all(&output)?;
+    fs::create_dir_all(output)?;
     Ok(())
 }
 
 fn write_config(output: &Path, config: &Config, interner: &Interner) -> Result<(), Error> {
     let path = output.join(file::CONFIG);
-    cprintln!("  Write full configuration to <b>{}</>.", path.display());
+    cprintln!(
+        "  Write full configuration to <b>{}</>.",
+        path.to_relative()?.display()
+    );
     let mut file = File::create(path)?;
     writeln!(file, "{:#}", config.resolve(interner).json())?;
     Ok(())
@@ -375,7 +384,7 @@ fn write_detail(output: &Path, details: &[detail::Tree]) -> Result<(), Error> {
     let path = output.join(file::DETAIL);
     cprintln!(
         "Write full trees analysis/filtering detail to <b>{}</>.",
-        path.display()
+        path.to_relative()?.display()
     );
     let mut file = File::create(path)?;
     writeln!(file, "{:#}", json!(details))?;
@@ -384,7 +393,10 @@ fn write_detail(output: &Path, details: &[detail::Tree]) -> Result<(), Error> {
 
 fn write_csv(output: &Path, details: &[detail::Tree]) -> Result<(), Error> {
     let path = output.join(file::CSV);
-    cprintln!("Summarize scalar values to <b>{}</>.", path.display());
+    cprintln!(
+        "Summarize scalar values to <b>{}</>.",
+        path.to_relative()?.display()
+    );
     let file = File::create(path)?;
     let mut wtr = csv::Writer::from_writer(file);
     for detail in details {
@@ -496,4 +508,6 @@ enum Error {
     Learn { source: aphid::learn::Error },
     #[snafu(display("Could not serialize record to CSV:\n{source}"))]
     Csv { source: csv::Error },
+    #[snafu(transparent)]
+    AphidIo { source: aphid::io::Error },
 }
diff --git a/src/config/deserialize.rs b/src/config/deserialize.rs
index 18b2700f71a6091971ce81051a3698c54fd2042d..f44fd121916e085d03f79d4e1786db975eaf8891 100644
--- a/src/config/deserialize.rs
+++ b/src/config/deserialize.rs
@@ -144,7 +144,7 @@ pub(crate) struct BfgsConfig {
 }
 
 #[derive(Deserialize)]
-#[serde(rename_all="snake_case")]
+#[serde(rename_all = "snake_case")]
 pub(crate) enum RecordTrace {
     No,
     Global,
diff --git a/src/io.rs b/src/io.rs
index bebe8cede22218993c7e5c62fb38088f49a795b9..ecb6b4b5dbb5e0db2bf4ba8bd99b1be84014f4fa 100644
--- a/src/io.rs
+++ b/src/io.rs
@@ -1,6 +1,8 @@
 // Reading from / writing to files on disk.
 
 use std::{
+    borrow::Cow,
+    env,
     fs::File,
     io::{self, Read},
     path::{Path, PathBuf},
@@ -25,6 +27,21 @@ pub fn canonicalize(path: &Path) -> Result<PathBuf, Error> {
         .with_context(|_| CanonicalizeErr { path })
 }
 
+// Display canonicalized paths relatively to current directory.
+pub trait ToRelative {
+    fn to_relative(&self) -> Result<Cow<Path>, Error>;
+}
+impl ToRelative for Path {
+    fn to_relative(&self) -> Result<Cow<Path>, Error> {
+        let cwd = env::current_dir().with_context(|_| CurDirErr)?;
+        Ok(if let Some(diff) = pathdiff::diff_paths(self, cwd) {
+            Cow::Owned(diff)
+        } else {
+            Cow::Borrowed(self)
+        })
+    }
+}
+
 #[derive(Debug, Snafu)]
 #[snafu(context(suffix(Err)))]
 pub enum Error {
@@ -40,4 +57,6 @@ pub enum Error {
         source: std::io::Error,
         path: PathBuf,
     },
+    #[snafu(display("Could not locate current directory: {source:?}"))]
+    CurDir { source: std::io::Error },
 }
diff --git a/src/learn.rs b/src/learn.rs
index 217db857e43e408309996c7708f880f06e84ef18..02ec07a9e58a3f2c7c638ed181e0d93c0b9705a1 100644
--- a/src/learn.rs
+++ b/src/learn.rs
@@ -11,6 +11,7 @@ use tch::{Device, Tensor};
 
 use crate::{
     config::Search,
+    io::{self, ToRelative},
     model::{
         likelihood::{data_tensors, ln_likelihood_tensors},
         parameters::GeneFlowTimes,
@@ -151,13 +152,13 @@ pub fn optimize_likelihood(
     if let Some(main) = &search.bfgs.main_trace_path {
         cprintln!(
             "  Recording main BFGS search trace at <b>{}</>.",
-            main.display()
+            main.to_relative()?.display()
         );
     }
     if let Some(lins) = &search.bfgs.linsearch_trace_path {
         cprintln!(
             "  Recording detailed Wolfe linear search traces at <b>{}</>.",
-            lins.display()
+            lins.to_relative()?.display()
         );
     }
     // Log every step if a file was provided.
@@ -177,7 +178,11 @@ pub fn optimize_likelihood(
          <g>{n_eval}</> evaluations and \
          <g>{n_diff}</> differentiations."
     );
-    cprintln!("<s>--</> Final location: <k,i>{}value 'gradient{}</>:\n{grad:#}", '<', '>');
+    cprintln!(
+        "<s>--</> Final location: <k,i>{}value 'gradient{}</>:\n{grad:#}",
+        '<',
+        '>'
+    );
 
     let parms: Parameters<f64> = (&scores).into();
     let opt_lnl = -opt.best_loss();
@@ -255,4 +260,6 @@ pub enum Error {
     NonFiniteLikelihood { lnl: f64, parms: Parameters<f64> },
     #[snafu(transparent)]
     Optim { source: OptimError },
+    #[snafu(transparent)]
+    IO { source: io::Error },
 }
diff --git a/src/lib.rs b/src/lib.rs
index ced4954e68919311934d4eda0e9efdf989bca24c..e07a4111bdd36d96c1ddda0ebc9129a2db59a7c4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,7 +2,7 @@ pub mod config;
 mod gene_tree;
 pub mod genes_forest;
 pub mod interner;
-mod io;
+pub mod io;
 pub mod it_mean;
 pub mod learn;
 mod lexer;
diff --git a/src/model/parameters.rs b/src/model/parameters.rs
index 3bc67951797084790d89b9190f070eecd725e456..ae55e8f59c477120dd1183f456dd22f360d0fb50 100644
--- a/src/model/parameters.rs
+++ b/src/model/parameters.rs
@@ -120,16 +120,16 @@ impl<F: Num + Display + Sized + fmt::Debug> Display for Colored<'_, F> {
             p_ancient,
             gf_times,
         } = &self.0;
-        cwriteln!(f, "  theta: <b>{theta:?}</>,")?;
-        cwriteln!(f, "  tau_1: <b>{tau_1:?}</>,")?;
-        cwriteln!(f, "  tau_2: <b>{tau_2:?}</>,")?;
-        cwriteln!(f, "  p_ab: <b>{p_ab:?}</>,")?;
-        cwriteln!(f, "  p_ac: <b>{p_ac:?}</>,")?;
-        cwriteln!(f, "  p_bc: <b>{p_bc:?}</>,")?;
-        cwriteln!(f, "  p_ancient: <b>{p_ancient:?}</>,")?;
+        cwriteln!(f, "  theta: <c>{theta:?}</>,")?;
+        cwriteln!(f, "  tau_1: <c>{tau_1:?}</>,")?;
+        cwriteln!(f, "  tau_2: <c>{tau_2:?}</>,")?;
+        cwriteln!(f, "  p_ab: <c>{p_ab:?}</>,")?;
+        cwriteln!(f, "  p_ac: <c>{p_ac:?}</>,")?;
+        cwriteln!(f, "  p_bc: <c>{p_bc:?}</>,")?;
+        cwriteln!(f, "  p_ancient: <c>{p_ancient:?}</>,")?;
         writeln!(f, "  gf_times: [")?;
         for t in &gf_times.0 {
-            cwriteln!(f, "    <b>{t}</>,")?;
+            cwriteln!(f, "    <c>{t}</>,")?;
         }
         writeln!(f, "  ]")?;
         writeln!(f, "}}")
diff --git a/src/output.rs b/src/output.rs
index 9bebdcd15b652c6a5cdb200392c198990e138e57..42391064f1d4bded5470c8a102bfb91a18268cf6 100644
--- a/src/output.rs
+++ b/src/output.rs
@@ -1,8 +1,8 @@
 // Use this module to specify the possible output(s) of aphid.
 
 mod config;
-pub mod detail;
 pub mod csv;
+pub mod detail;
 
 // Standard output filenames.
 pub mod file {
@@ -12,4 +12,3 @@ pub mod file {
     pub const MAIN_TRACE: &str = "search_global.csv";
     pub const LINSEARCH_TRACE: &str = "search_detail.csv";
 }
-