diff --git a/Makefile.am b/Makefile.am
index 63456ca4..c0e5c8c2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -72,4 +72,3 @@ include ui/test/Makefile.am
 include man/Makefile.am
 
 include utils/Makefile.am
-
diff --git a/configure.ac b/configure.ac
index 4151b002..3d7e9964 100644
--- a/configure.ac
+++ b/configure.ac
@@ -450,6 +450,15 @@ esac
 
 AC_DEFINE_UNQUOTED(TFTP_TYPE, $tftp_type, [tftp client type])
 
+AC_ARG_VAR(
+	[CARGO_OPTS],
+	[Arguments to cargo]
+)
+AC_ARG_VAR(
+	[RUSTC_TARGET_NAME],
+	[Target as passed to cargo]
+)
+
 default_cflags="--std=gnu99 -g \
 	-Wall -W -Wunused -Wstrict-prototypes -Wmissing-prototypes \
 	-Wmissing-declarations -Wredundant-decls"
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 69a66c37..87fe38d6 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -12,6 +12,8 @@
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
+include lib/rust/Makefile.am
+
 core_lib = lib/libpbcore.la
 
 noinst_LTLIBRARIES += $(core_lib)
@@ -70,7 +72,12 @@ lib_libpbcore_la_SOURCES = \
 	lib/efi/efivar.h \
 	lib/efi/efivar.c \
 	lib/param_list/param_list.c \
-	lib/param_list/param_list.h
+	lib/param_list/param_list.h \
+	lib/rust/rustlibs.c \
+	lib/rust/rustlibs.c
+
+lib_libpbcore_la_LIBADD = \
+	$(rust_lib)
 
 if ENABLE_MTD
 lib_libpbcore_la_SOURCES += \
diff --git a/lib/rust/Cargo.lock b/lib/rust/Cargo.lock
new file mode 100644
index 00000000..5b375927
--- /dev/null
+++ b/lib/rust/Cargo.lock
@@ -0,0 +1,117 @@
+[[package]]
+name = "dtoa"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "itoa"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libtool"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "num-traits"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "proc-macro2"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustlibs"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libtool 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde_derive"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive_internals 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_derive_internals"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syn"
+version = "0.12.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
+"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
+"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
+"checksum libtool 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f576520ad5e2848b26568964320a4073984db2a11147ac4f9c2fc7be1f93b8d2"
+"checksum num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3c2bd9b9d21e48e956b763c9f37134dc62d9e95da6edb3f672cacb6caf3cd3"
+"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
+"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
+"checksum serde 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "e928fecdb00fe608c96f83a012633383564e730962fc7a0b79225a6acf056798"
+"checksum serde_derive 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "95f666a2356d87ce4780ea15b14b13532785579a5cad2dcba5292acc75f6efe2"
+"checksum serde_derive_internals 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fc848d073be32cd982380c06587ea1d433bc1a4c4a111de07ec2286a3ddade8"
+"checksum serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57781ed845b8e742fc2bf306aba8e3b408fe8c366b900e3769fbc39f49eb8b39"
+"checksum syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)" = "517f6da31bc53bf080b9a77b29fbd0ff8da2f5a2ebd24c73c2238274a94ac7cb"
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
diff --git a/lib/rust/Cargo.toml b/lib/rust/Cargo.toml
new file mode 100644
index 00000000..c335d1bb
--- /dev/null
+++ b/lib/rust/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "rustlibs"
+build = "build.rs"
+version = "0.1.0"
+authors = ["Samuel Mendoza-Jonas <sam@mendozajonas.com>"]
+
+[dependencies]
+serde = "1.0"
+serde_derive = "1.0"
+serde_json = "1.0"
+libc = "0.2"
+
+[lib]
+crate-type = ["staticlib"]
+
+[build-dependencies]
+libtool = "0.1"
+
+[profile.release]
+lto = true
diff --git a/lib/rust/Makefile.am b/lib/rust/Makefile.am
new file mode 100644
index 00000000..add42ff2
--- /dev/null
+++ b/lib/rust/Makefile.am
@@ -0,0 +1,30 @@
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; version 2 of the License.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+rust_lib = librustlibs.la
+
+noinst_LTLIBRARIES += $(rust_lib)
+
+librustlibs_la_SOURCES = ""
+
+CARGO_TARGET_DIR := $(abs_top_builddir)/lib/rust
+
+$(rust_lib):
+	CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) cargo build --release --manifest-path $(top_srcdir)/lib/rust/Cargo.toml $(CARGO_OPTS)
+	ln -sf $(CARGO_TARGET_DIR)/$(RUSTC_TARGET_NAME)/release/librustlibs.a
+	ln -sf $(CARGO_TARGET_DIR)/$(RUSTC_TARGET_NAME)/release/librustlibs.la
+	ln -sf $(CARGO_TARGET_DIR)/$(RUSTC_TARGET_NAME)/release/.libs
+
+clean-local:
+	CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) cargo clean --manifest-path $(top_srcdir)/lib/rust/Cargo.toml
diff --git a/lib/rust/build.rs b/lib/rust/build.rs
new file mode 100644
index 00000000..513e119f
--- /dev/null
+++ b/lib/rust/build.rs
@@ -0,0 +1,70 @@
+/*
+ * From https://docs.rs/libtool/0.1.1/libtool/
+ * Upstream doesn't handle some of the directory structure we use in Petitboot,
+ * use a few extra environment variables to properly determine the target paths.
+ */
+
+use std::env;
+use std::fs::File;
+use std::fs;
+use std::io::prelude::*;
+use std::os::unix::fs::symlink;
+use std::path::PathBuf;
+
+/// Generate libtool archive file ${lib}.la
+pub fn generate_convenience_lib(lib: &str) -> std::io::Result<()> {
+    let self_version = env!("CARGO_PKG_VERSION");
+    let profile = env::var("PROFILE").unwrap();
+    let target_arch = env::var("TARGET").unwrap();
+    let target_dir_env = env::var("CARGO_TARGET_DIR").unwrap();
+
+    /* Check if the output directory will include the arch */
+    let target_dir = if PathBuf::from(format!("{}/{}",
+                                target_dir_env, target_arch)).exists() {
+        format!("{}/{}/{}", target_dir_env, target_arch, profile)
+    } else {
+        format!("{}/{}", target_dir_env, profile)
+    };
+
+    /* Location of original static library */
+    let old_lib_path = PathBuf::from(format!("{}/{}.a",
+                                            target_dir, lib));
+    /* Paths for new .la file and symlinks */
+    let libs_dir = format!("{}/.libs", target_dir);
+    let libs_path = PathBuf::from(&libs_dir);
+    let la_path = PathBuf::from(format!("{}/{}.la",
+                                        target_dir, lib));
+    let new_lib_path = PathBuf::from(format!("{}/{}.a", libs_dir, lib));
+
+    match fs::create_dir_all(&libs_path) {
+        Ok(()) => println!("libs_path created"),
+        _ => panic!("Failed to create libs_path"),
+    }
+
+    if la_path.exists() {
+        fs::remove_file(&la_path)?;
+    }
+
+    /* PathBuf.exists() traverses symlinks so just try and remove it */
+    match fs::remove_file(&new_lib_path) {
+        Ok(_v) => {},
+        Err(e) => println!("Error removing symlink: {:?}", e),
+    }
+
+    let mut file = File::create(&la_path)?;
+    writeln!(file, "# {}.la - a libtool library file", lib)?;
+    writeln!(file, "# Generated by libtool-rust {}", self_version)?;
+    writeln!(file, "dlname=''")?;
+    writeln!(file, "library_names=''")?;
+    writeln!(file, "old_library='{}.a'", lib)?;
+    writeln!(file, "inherited_linker_flags=' -pthread -lm -ldl'")?;
+    writeln!(file, "installed=no")?;
+    writeln!(file, "shouldnotlink=no")?;
+
+    symlink(&old_lib_path, &new_lib_path)?;
+    Ok(())
+}
+
+fn main() {
+    generate_convenience_lib("librustlibs").unwrap();
+}
diff --git a/lib/rust/rustlibs.c b/lib/rust/rustlibs.c
new file mode 100644
index 00000000..fe686bef
--- /dev/null
+++ b/lib/rust/rustlibs.c
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (C) 2018 IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+#include <log/log.h>
+#include <talloc/talloc.h>
+
+#include "rustlibs.h"
+
+enum field_type {
+	FIELD_STR,
+	FIELD_I64,
+	FIELD_F64,
+};
+
+/* Internal FFI Structs */
+struct ArgumentRaw {
+	char		*name;
+	enum field_type type;
+	int64_t		arg_i64;
+	double		arg_f64;
+	char		*arg_str;
+};
+
+struct CommandRaw {
+	char			*platform;
+	char			*name;
+	char			*cmd;
+	char			*args_fmt;
+	struct ArgumentRaw	*args;
+	size_t			n_args;
+	char			*help;
+};
+
+struct CommandArray {
+	struct CommandRaw	*commands;
+	size_t			len;
+};
+
+/* Provided by librustlibs */
+struct CommandArray *parse_json(const char *filename);
+void free_command_array(struct CommandArray *commands);
+
+int parse_command_file(void *ctx, const char *path, struct command **commands)
+{
+	struct CommandArray *raw_commands;
+	struct CommandRaw *tmp;
+	struct command *new;
+	struct argument *arg;
+	unsigned int i, j, len;
+
+	raw_commands = parse_json(path);
+	if (!raw_commands) {
+		pb_log("Failed to parse machine command\n");
+		return 0;
+	}
+
+	len = raw_commands->len;
+	new = talloc_zero_array(ctx, struct command, len);
+	for (i = 0; i < len; i++) {
+		tmp = &raw_commands->commands[i];
+		new[i].platform = talloc_strdup(new, tmp->platform);
+		new[i].name = talloc_strdup(new, tmp->name);
+		new[i].cmd = talloc_strdup(new, tmp->cmd);
+		new[i].args_fmt = talloc_strdup(new, tmp->args_fmt);
+
+		new[i].n_args = tmp->n_args;
+		new[i].args = talloc_zero_array(new, struct argument,
+				new[i].n_args);
+		for (j = 0; j < tmp->n_args; j++) {
+			arg = &new[i].args[j];
+			arg->name = talloc_strdup(new, tmp->args[j].name);
+			arg->type = tmp->args[j].type;
+			switch (tmp->args[j].type) {
+			case FIELD_STR:
+				arg->arg_str = talloc_strdup(new,
+						tmp->args[j].arg_str);
+				break;
+			case FIELD_I64:
+				arg->arg_i64 = tmp->args[j].arg_i64;
+				break;
+			case FIELD_F64:
+				arg->arg_f64 = tmp->args[j].arg_f64;
+				break;
+			default:
+				pb_log_fn("Unknown field type %d for arg '%s'\n",
+						tmp->args[j].type, tmp->args[j].name);
+				break;
+			}
+		}
+
+		new[i].help = talloc_strdup(new, tmp->help);
+	}
+
+	free_command_array(raw_commands);
+
+	*commands = new;
+	return len;
+}
diff --git a/lib/rust/rustlibs.h b/lib/rust/rustlibs.h
new file mode 100644
index 00000000..0246657b
--- /dev/null
+++ b/lib/rust/rustlibs.h
@@ -0,0 +1,11 @@
+#ifndef __RUST_LIBS__
+#define __RUST_LIBS__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <types/types.h>
+
+int parse_command_file(void *ctx, const char *path, struct command **commands);
+
+#endif /* __RUST_LIBS__ */
diff --git a/lib/rust/src/lib.rs b/lib/rust/src/lib.rs
new file mode 100644
index 00000000..5f4b484b
--- /dev/null
+++ b/lib/rust/src/lib.rs
@@ -0,0 +1,230 @@
+#[macro_use]
+extern crate serde_derive;
+
+extern crate serde;
+extern crate serde_json;
+extern crate libc;
+
+use std::ffi::CString;
+use std::ffi::CStr;
+use std::os::raw::c_char;
+use std::fs::File;
+use std::path::Path;
+use std::ptr;
+use std::mem;
+use libc::{c_long, c_double};
+
+/* Rust representations */
+#[derive(Serialize, Deserialize, Debug)]
+pub struct Command {
+	platform:	CString,
+	name:		CString,
+    cmd:        CString,
+    arg_fmt:    CString,
+    args:       Vec<Argument>,
+    help:       CString,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+enum FieldType {
+    FieldString(CString),
+    // TODO Commands which display as yes/no that hide some actual command?
+    // FieldBool(Bool),
+    FieldInt(i64),
+    FieldFloat(f64),
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct Argument {
+    name:           CString,
+    arg:            FieldType,
+}
+
+/* FFI respresentations */
+#[repr(C)]
+pub struct CommandArray {
+    bytes:  *mut CommandRaw,
+    len:    usize,
+}
+
+#[repr(C)]
+pub struct CommandRaw {
+    platform:   *mut c_char,
+    name:       *mut c_char,
+    cmd:        *mut c_char,
+    arg_fmt:    *mut c_char,
+    args:       *mut ArgumentRaw,
+    n_args:     usize,
+    help:       *mut c_char,
+}
+
+impl CommandRaw {
+    /*
+     * We need to convert several fields into FFI-suitable types and we
+     * don't want to 'partially forget' the Command structs, so we
+     * clone the various fields and forget them. The vec is then shrunk
+     * and forgotten so it can be passed as an array C will recognise.
+     */
+    fn new(command: &Command) -> CommandRaw {
+        CommandRaw {
+            platform: command.platform.clone().into_raw(),
+            name: command.name.clone().into_raw(),
+            cmd: command.cmd.clone().into_raw(),
+            arg_fmt: command.arg_fmt.clone().into_raw(),
+            args: CommandRaw::args_into_raw(&command.args),
+            n_args: command.args.len(),
+            help: command.help.clone().into_raw()
+        }
+    }
+
+    fn args_into_raw(args: &Vec<Argument>) -> *mut ArgumentRaw {
+
+        let mut args_raw  = Vec::<ArgumentRaw>::new();
+
+        for arg in args {
+            let raw_arg = ArgumentRaw::new(&arg);
+            args_raw.push(raw_arg);
+        }
+
+        args_raw.shrink_to_fit();
+        let ptr = args_raw.as_mut_ptr();
+        mem::forget(args_raw);
+
+        return ptr;
+    }
+}
+
+#[repr(C)]
+/*
+ * Rust enums are not C enums and Rust doesn't have a 'union' concept like in C
+ * so we just declare all the fields here and set them based on arg_type.
+ */
+pub struct ArgumentRaw {
+    name:       *mut c_char,
+    arg_type:   FieldTypeRaw,
+    arg_i64:    c_long,
+    arg_f64:    c_double,
+    arg_str:    *mut c_char,
+}
+
+impl ArgumentRaw {
+    fn new(arg: &Argument) -> ArgumentRaw {
+        let raw_arg = match arg.arg {
+            FieldType::FieldString(ref s) => {
+                ArgumentRaw {
+                    name: arg.name.clone().into_raw(),
+                    arg_type: FieldTypeRaw::RawString,
+                    arg_i64: 0,
+                    arg_f64: 0.0,
+                    arg_str: s.clone().into_raw(),
+                }
+            },
+            FieldType::FieldInt(i) => {
+                ArgumentRaw {
+                    name: arg.name.clone().into_raw(),
+                    arg_type: FieldTypeRaw::RawInt,
+                    arg_i64: i,
+                    arg_f64: 0.0,
+                    arg_str: ptr::null_mut(),
+                }
+            },
+            FieldType::FieldFloat(f) => {
+                ArgumentRaw {
+                    name: arg.name.clone().into_raw(),
+                    arg_type: FieldTypeRaw::RawFloat,
+                    arg_i64: 0,
+                    arg_f64: f,
+                    arg_str: ptr::null_mut(),
+                }
+            },
+        };
+        return raw_arg;
+    }
+}
+
+#[repr(C)]
+#[derive(PartialEq)]
+enum FieldTypeRaw {
+    RawString = 0,
+    RawInt,
+    RawFloat,
+}
+
+/*
+ * Take a CommandArray pointer from C and reclaim the CommandRaw
+ * structs and their members/
+ * We can't avoid the unsafe {} invocations since we're reading arbitrary
+ * memory, but it's contained to this function.
+ */
+#[no_mangle]
+pub extern fn free_command_array(commands: *mut CommandArray) {
+
+    let ptr = unsafe { Box::from_raw(commands) };
+    let raw_vec = unsafe { Vec::from_raw_parts(ptr.bytes,
+                                               ptr.len,
+                                               ptr.len) };
+    for raw_command in raw_vec.iter() {
+        unsafe {
+            let _platform = CString::from_raw(raw_command.platform);
+            let _name = CString::from_raw(raw_command.name);
+            let _cmd = CString::from_raw(raw_command.cmd);
+            let _arg_fmt = CString::from_raw(raw_command.arg_fmt);
+            /* n_args  */
+            let arg_vec = Vec::from_raw_parts(raw_command.args,
+                                              raw_command.n_args,
+                                              raw_command.n_args);
+            for raw_arg in arg_vec.iter() {
+                let _name = CString::from_raw(raw_arg.name);
+                if raw_arg.arg_type == FieldTypeRaw::RawString {
+                    let _arg_str = CString::from_raw(raw_arg.arg_str);
+                }
+            }
+            let _help = CString::from_raw(raw_command.help);
+        }
+    }
+
+    /* Frees once it goes out of scope */
+    println!("Rust reclaimed {} command structs", raw_vec.len());
+}
+
+#[no_mangle]
+pub extern fn parse_json(filename: *const c_char) -> *mut CommandArray {
+
+    let file: String;
+    unsafe {
+        /* Can't trust the promise of a string from C */
+        file = CStr::from_ptr(filename).to_string_lossy().into_owned();
+    }
+
+    let json_path = Path::new(&file);
+    let json_file = match File::open(json_path) {
+        Err(e) => {
+            println!("Could not open file: {}", e);
+            return ptr::null_mut();
+        }
+        Ok(f) => f,
+    };
+
+    let commands: Vec<Command> = match serde_json::from_reader(json_file) {
+        Err(e) => {
+            println!("Could not parse JSON: {}", e);
+            return ptr::null_mut();
+        }
+        Ok(c) =>  c,
+    };
+
+    /* Convert commands into a form more easily passed to C */
+    let mut ffi_vec = Vec::<CommandRaw>::new();
+    for command in commands.iter() {
+        let raw_command = CommandRaw::new(&command);
+        ffi_vec.push(raw_command);
+    }
+
+    let len = ffi_vec.len();
+    ffi_vec.shrink_to_fit();
+    let ffi_ptr = ffi_vec.as_mut_ptr();
+    mem::forget(ffi_vec);
+
+    let wrapper = Box::new(CommandArray { bytes: ffi_ptr, len: len });
+    return Box::into_raw(wrapper);
+}
diff --git a/lib/types/types.h b/lib/types/types.h
index 9d83d87d..6e5fb7d3 100644
--- a/lib/types/types.h
+++ b/lib/types/types.h
@@ -66,6 +66,32 @@ struct boot_option {
 	} type;
 };
 
+enum cmd_arg_type {
+	ARG_STR,
+	ARG_I64,
+	ARG_F64,
+};
+
+struct argument {
+	char			*name;
+	enum cmd_arg_type	type;
+	union {
+		char		*arg_str;
+		int64_t		arg_i64;
+		double		arg_f64;
+	};
+};
+
+struct command {
+	char			*platform;
+	char			*name;
+	char			*cmd;
+	char			*args_fmt;
+	unsigned int		n_args;
+	struct argument		*args;
+	char			*help;
+};
+
 struct plugin_option {
 	char		*id;
 	char		*name;
@@ -74,10 +100,14 @@ struct plugin_option {
 	char		*version;
 	char		*date;
 	char		*plugin_file;
+	char		*command_file;
 
 	unsigned int	n_executables;
 	char		**executables;
 
+	unsigned int	n_commands;
+	struct command	*commands;
+
 	void		*ui_info;
 };
 
