diff --git a/CMakeLists.txt b/CMakeLists.txt
index f9cacd3..7114332 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,29 +15,32 @@ if(WIRING_PI_DEBUG)
     add_compile_definitions("WIRING_PI_DEBUG")
 endif(WIRING_PI_DEBUG)
 
+aux_source_directory(vendor VENDOR_SRC) # vendor first to put their warnings on top
 aux_source_directory(. SRC_DIR)
 aux_source_directory(models MODELS_SRC)
 aux_source_directory(helpers HELPERS_SRC)
 aux_source_directory(handlers HANDLERS_SRC)
 aux_source_directory(drivers DRIVERS_SRC)
+aux_source_directory(runners RUNNERS_SRC)
 
 configure_file("controller.ini" "controller.ini" COPYONLY)
 
-target_sources(controller PRIVATE ${SRC_DIR} ${MODELS_SRC} ${HELPERS_SRC} ${HANDLERS_SRC} ${DRIVERS_SRC})
+target_sources(controller PRIVATE ${VENDOR_SRC} ${SRC_DIR} ${MODELS_SRC} ${HELPERS_SRC} ${HANDLERS_SRC} ${DRIVERS_SRC} ${RUNNERS_SRC})
 target_include_directories(controller PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+target_include_directories(controller PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vendor)
 
 add_custom_target(run
-    COMMAND ./controller
+    COMMAND ./controller start
     DEPENDS controller
     WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 )
 add_custom_target(debug
-    COMMAND valgrind ./controller
+    COMMAND valgrind ./controller start
     DEPENDS controller
     WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 )
 add_custom_target(debug-full
-    COMMAND valgrind --leak-check=full --show-leak-kinds=all ./controller
+    COMMAND valgrind --leak-check=full --show-leak-kinds=all ./controller start
     DEPENDS controller
     WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
 )
diff --git a/helpers/parse_cli.c b/helpers/parse_cli.c
new file mode 100644
index 0000000..7f9c094
--- /dev/null
+++ b/helpers/parse_cli.c
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <argparse.h>
+#include <config.h>
+#include <logger.h>
+#include <helpers.h>
+
+static const char *const usage[] = {
+    "controller [options] [[--] args]",
+    "controller [options]",
+    NULL,
+};
+
+#define PERM_READ  (1<<0)
+#define PERM_WRITE (1<<1)
+#define PERM_EXEC  (1<<2)
+
+void
+helpers_parse_cli(int argc, const char **argv, config_t *config)
+{
+    struct argparse_option options[] =
+    {
+        OPT_HELP(),
+        OPT_GROUP("Basic options"),
+        OPT_STRING('c', "config", &config->file, "path to config file", NULL, 0, OPT_NONEG),
+
+        OPT_END(),
+    };
+
+    struct argparse argparse;
+    argparse_init(&argparse, options, usage, 0);
+    argparse_describe(
+            &argparse,
+            "\nA brief description of what the program does and how it works.",
+            "\nAdditional description of the program after the description of the arguments."
+    );
+    argc = argparse_parse(&argparse, argc, argv);
+
+    if(argc == 1)
+    {
+        if(strcmp(argv[0], "start") == 0)
+        {
+            config->run_type = RUN_TYPE_START;
+            return;
+        }
+        if(strcmp(argv[0], "test") == 0)
+        {
+            config->run_type = RUN_TYPE_TEST;
+            return;
+        }
+        LOG_FATAL("bad action '%s' given ('start', 'test')", argv[0]);
+        exit(1);
+    }
+    else
+    {
+        LOG_FATAL("no action given ('start', 'test')");
+        exit(1);
+    }
+    return;
+}
diff --git a/include/config.h b/include/config.h
index 24da946..fb7eac6 100644
--- a/include/config.h
+++ b/include/config.h
@@ -14,6 +14,8 @@ typedef struct
 
 typedef struct
 {
+    char *file;
+    run_type_t run_type;
     char name[MAX_NAME_LENGTH + 1];
     uint16_t discovery_port;
     uint8_t relay_count;
diff --git a/include/enums.h b/include/enums.h
index 87f093f..c461215 100644
--- a/include/enums.h
+++ b/include/enums.h
@@ -39,9 +39,15 @@ typedef enum
 
 typedef enum
 {
-    RELAY_DRIVER_NONE = 0,
-    RELAY_DRIVER_GPIO = 1,
-    RELAY_DRIVER_PIFACE = 2,
+    RELAY_DRIVER_NONE,
+    RELAY_DRIVER_GPIO,
+    RELAY_DRIVER_PIFACE,
 } relay_driver_t;
 
+typedef enum
+{
+    RUN_TYPE_START,
+    RUN_TYPE_TEST,
+} run_type_t;
+
 #endif /* CONTROLLER_ENUMS_H */
diff --git a/include/helpers.h b/include/helpers.h
index 4a599fd..49d2a6f 100644
--- a/include/helpers.h
+++ b/include/helpers.h
@@ -2,6 +2,7 @@
 #define CONTROLLER_HELPERS_H
 
 #include <confini.h>
+#include <config.h>
 
 int
 helper_connect_tcp_server(char* host, uint16_t port);
@@ -27,4 +28,7 @@ helper_open_discovery_socket(uint16_t discovery_port);
 int
 helper_load_config(IniDispatch *disp, void *config_void);
 
+void
+helpers_parse_cli(int argc, const char **argv, config_t *config);
+
 #endif /* CONTROLLER_HELPERS_H */
diff --git a/include/runners.h b/include/runners.h
new file mode 100644
index 0000000..ce74bd2
--- /dev/null
+++ b/include/runners.h
@@ -0,0 +1,11 @@
+#ifndef CONTROLLER_RUNNERS_H
+#define CONTROLLER_RUNNERS_H
+
+#include <stdint.h>
+
+#include <models/controller.h>
+
+void
+runner_test(controller_t *controller);
+
+#endif /* CONTROLLER_RUNNERS_H */
diff --git a/include/wiring_debug.h b/include/wiring_debug.h
index cb77f65..664d88b 100644
--- a/include/wiring_debug.h
+++ b/include/wiring_debug.h
@@ -3,7 +3,7 @@
 
 #include <logger.h>
 
-#define LOG_WIRING_DEBUG(x, ...) LOG_TRACE(x, ##__VA_ARGS__)
+#define LOG_WIRING_DEBUG(x, ...) LOG_DEBUG(x, ##__VA_ARGS__)
 
 #ifdef WIRING_PI_DEBUG
     #define wiringPiSetup() LOG_WIRING_DEBUG("wiringPi wiringPiSetup()")
diff --git a/main.c b/main.c
index 5a233a2..42b1e4f 100644
--- a/main.c
+++ b/main.c
@@ -16,6 +16,7 @@
 #include <handlers.h>
 #include <drivers.h>
 #include <enums.h>
+#include <runners.h>
 #include <helpers.h>
 #include <wiringPi.h>
 #include <piFace.h>
@@ -56,7 +57,7 @@ terminate(int signum)
  * @return Statuscode to indicate success (0) or failure (!0)
  */
 int
-main(int argc, char** argv)
+main(int argc, const char** argv)
 {
     (void)argc;
     (void)argv;
@@ -67,16 +68,19 @@ main(int argc, char** argv)
 
     /******************** LOAD CONFIG ********************/
 
-    char ini_file_name[] = "controller.ini";
-    FILE * const ini_file = fopen(ini_file_name, "rb");
+    global_config.file = "controller.ini";
+
+    helpers_parse_cli(argc, argv, &global_config);
+
+    FILE * const ini_file = fopen(global_config.file, "rb");
     if(ini_file == NULL)
     {
-        LOG_ERROR("%s file was not found", ini_file_name);
+        LOG_FATAL("config file '%s' was not found", global_config.file);
         exit(1);
     }
     if(load_ini_file( ini_file, INI_DEFAULT_FORMAT, NULL, helper_load_config, &global_config))
     {
-        LOG_ERROR("unable to parse ini file");
+        LOG_FATAL("unable to parse ini file");
         exit(1);
     }
  
@@ -120,6 +124,15 @@ main(int argc, char** argv)
     poll_fds[POLL_FDS_COMMAND].events = POLLIN;
     LOG_DEBUG("setup fd_command as %i on index %i", fd_command, POLL_FDS_COMMAND);
 
+
+    /******************** CHECK FOR TESTING RUN ********************/
+
+    if(global_config.run_type == RUN_TYPE_TEST)
+    {
+        runner_test(this_controller);
+    }
+    
+
     /******************** START MAIN LOOP ********************/
 
     for(;;)
diff --git a/runners/test.c b/runners/test.c
new file mode 100644
index 0000000..5f22830
--- /dev/null
+++ b/runners/test.c
@@ -0,0 +1,30 @@
+#include <unistd.h>   
+
+#include <runners.h>
+#include <logger.h>
+#include <drivers.h>
+#include <drivers.h>
+
+void
+runner_test(controller_t *controller)
+{
+    // from x down to 0 to turn all relays off in the end
+    for(int test_run = 2; test_run >= 0; --test_run)
+    {
+        for(uint_fast8_t i = 0; i < controller->relay_count; ++i)
+        {
+            switch(global_config.relay_configs[i].driver)
+            {
+                case RELAY_DRIVER_GPIO:
+                    driver_gpio_set(global_config.relay_configs[i].pin, test_run % 2);
+                    break;
+                case RELAY_DRIVER_PIFACE:
+                    driver_piface_set(global_config.relay_configs[i].pin, test_run % 2);
+                    break;
+                default:
+                    LOG_WARN("relay %d is not using a driver", i);
+            }
+            sleep(1);
+        }
+    }
+}
diff --git a/vendor/argparse.c b/vendor/argparse.c
new file mode 100644
index 0000000..ec86bba
--- /dev/null
+++ b/vendor/argparse.c
@@ -0,0 +1,384 @@
+/**
+ * Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
+ * All rights reserved.
+ *
+ * Use of this source code is governed by a MIT-style license that can be found
+ * in the LICENSE file.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include "argparse.h"
+
+#define OPT_UNSET 1
+#define OPT_LONG  (1 << 1)
+
+static const char *
+prefix_skip(const char *str, const char *prefix)
+{
+    size_t len = strlen(prefix);
+    return strncmp(str, prefix, len) ? NULL : str + len;
+}
+
+static int
+prefix_cmp(const char *str, const char *prefix)
+{
+    for (;; str++, prefix++)
+        if (!*prefix) {
+            return 0;
+        } else if (*str != *prefix) {
+            return (unsigned char)*prefix - (unsigned char)*str;
+        }
+}
+
+static void
+argparse_error(struct argparse *self, const struct argparse_option *opt,
+               const char *reason, int flags)
+{
+    (void)self;
+    if (flags & OPT_LONG) {
+        fprintf(stderr, "error: option `--%s` %s\n", opt->long_name, reason);
+    } else {
+        fprintf(stderr, "error: option `-%c` %s\n", opt->short_name, reason);
+    }
+    exit(1);
+}
+
+static int
+argparse_getvalue(struct argparse *self, const struct argparse_option *opt,
+                  int flags)
+{
+    const char *s = NULL;
+    if (!opt->value)
+        goto skipped;
+    switch (opt->type) {
+    case ARGPARSE_OPT_BOOLEAN:
+        if (flags & OPT_UNSET) {
+            *(int *)opt->value = *(int *)opt->value - 1;
+        } else {
+            *(int *)opt->value = *(int *)opt->value + 1;
+        }
+        if (*(int *)opt->value < 0) {
+            *(int *)opt->value = 0;
+        }
+        break;
+    case ARGPARSE_OPT_BIT:
+        if (flags & OPT_UNSET) {
+            *(int *)opt->value &= ~opt->data;
+        } else {
+            *(int *)opt->value |= opt->data;
+        }
+        break;
+    case ARGPARSE_OPT_STRING:
+        if (self->optvalue) {
+            *(const char **)opt->value = self->optvalue;
+            self->optvalue             = NULL;
+        } else if (self->argc > 1) {
+            self->argc--;
+            *(const char **)opt->value = *++self->argv;
+        } else {
+            argparse_error(self, opt, "requires a value", flags);
+        }
+        break;
+    case ARGPARSE_OPT_INTEGER:
+        errno = 0;
+        if (self->optvalue) {
+            *(int *)opt->value = strtol(self->optvalue, (char **)&s, 0);
+            self->optvalue     = NULL;
+        } else if (self->argc > 1) {
+            self->argc--;
+            *(int *)opt->value = strtol(*++self->argv, (char **)&s, 0);
+        } else {
+            argparse_error(self, opt, "requires a value", flags);
+        }
+        if (errno)
+            argparse_error(self, opt, strerror(errno), flags);
+        if (s[0] != '\0')
+            argparse_error(self, opt, "expects an integer value", flags);
+        break;
+    case ARGPARSE_OPT_FLOAT:
+        errno = 0;
+        if (self->optvalue) {
+            *(float *)opt->value = strtof(self->optvalue, (char **)&s);
+            self->optvalue       = NULL;
+        } else if (self->argc > 1) {
+            self->argc--;
+            *(float *)opt->value = strtof(*++self->argv, (char **)&s);
+        } else {
+            argparse_error(self, opt, "requires a value", flags);
+        }
+        if (errno)
+            argparse_error(self, opt, strerror(errno), flags);
+        if (s[0] != '\0')
+            argparse_error(self, opt, "expects a numerical value", flags);
+        break;
+    default:
+        assert(0);
+    }
+
+skipped:
+    if (opt->callback) {
+        return opt->callback(self, opt);
+    }
+
+    return 0;
+}
+
+static void
+argparse_options_check(const struct argparse_option *options)
+{
+    for (; options->type != ARGPARSE_OPT_END; options++) {
+        switch (options->type) {
+        case ARGPARSE_OPT_END:
+        case ARGPARSE_OPT_BOOLEAN:
+        case ARGPARSE_OPT_BIT:
+        case ARGPARSE_OPT_INTEGER:
+        case ARGPARSE_OPT_FLOAT:
+        case ARGPARSE_OPT_STRING:
+        case ARGPARSE_OPT_GROUP:
+            continue;
+        default:
+            fprintf(stderr, "wrong option type: %d", options->type);
+            break;
+        }
+    }
+}
+
+static int
+argparse_short_opt(struct argparse *self, const struct argparse_option *options)
+{
+    for (; options->type != ARGPARSE_OPT_END; options++) {
+        if (options->short_name == *self->optvalue) {
+            self->optvalue = self->optvalue[1] ? self->optvalue + 1 : NULL;
+            return argparse_getvalue(self, options, 0);
+        }
+    }
+    return -2;
+}
+
+static int
+argparse_long_opt(struct argparse *self, const struct argparse_option *options)
+{
+    for (; options->type != ARGPARSE_OPT_END; options++) {
+        const char *rest;
+        int opt_flags = 0;
+        if (!options->long_name)
+            continue;
+
+        rest = prefix_skip(self->argv[0] + 2, options->long_name);
+        if (!rest) {
+            // negation disabled?
+            if (options->flags & OPT_NONEG) {
+                continue;
+            }
+            // only OPT_BOOLEAN/OPT_BIT supports negation
+            if (options->type != ARGPARSE_OPT_BOOLEAN && options->type !=
+                ARGPARSE_OPT_BIT) {
+                continue;
+            }
+
+            if (prefix_cmp(self->argv[0] + 2, "no-")) {
+                continue;
+            }
+            rest = prefix_skip(self->argv[0] + 2 + 3, options->long_name);
+            if (!rest)
+                continue;
+            opt_flags |= OPT_UNSET;
+        }
+        if (*rest) {
+            if (*rest != '=')
+                continue;
+            self->optvalue = rest + 1;
+        }
+        return argparse_getvalue(self, options, opt_flags | OPT_LONG);
+    }
+    return -2;
+}
+
+int
+argparse_init(struct argparse *self, struct argparse_option *options,
+              const char *const *usages, int flags)
+{
+    memset(self, 0, sizeof(*self));
+    self->options     = options;
+    self->usages      = usages;
+    self->flags       = flags;
+    self->description = NULL;
+    self->epilog      = NULL;
+    return 0;
+}
+
+void
+argparse_describe(struct argparse *self, const char *description,
+                  const char *epilog)
+{
+    self->description = description;
+    self->epilog      = epilog;
+}
+
+int
+argparse_parse(struct argparse *self, int argc, const char **argv)
+{
+    self->argc = argc - 1;
+    self->argv = argv + 1;
+    self->out  = argv;
+
+    argparse_options_check(self->options);
+
+    for (; self->argc; self->argc--, self->argv++) {
+        const char *arg = self->argv[0];
+        if (arg[0] != '-' || !arg[1]) {
+            if (self->flags & ARGPARSE_STOP_AT_NON_OPTION) {
+                goto end;
+            }
+            // if it's not option or is a single char '-', copy verbatim
+            self->out[self->cpidx++] = self->argv[0];
+            continue;
+        }
+        // short option
+        if (arg[1] != '-') {
+            self->optvalue = arg + 1;
+            switch (argparse_short_opt(self, self->options)) {
+            case -1:
+                break;
+            case -2:
+                goto unknown;
+            }
+            while (self->optvalue) {
+                switch (argparse_short_opt(self, self->options)) {
+                case -1:
+                    break;
+                case -2:
+                    goto unknown;
+                }
+            }
+            continue;
+        }
+        // if '--' presents
+        if (!arg[2]) {
+            self->argc--;
+            self->argv++;
+            break;
+        }
+        // long option
+        switch (argparse_long_opt(self, self->options)) {
+        case -1:
+            break;
+        case -2:
+            goto unknown;
+        }
+        continue;
+
+unknown:
+        fprintf(stderr, "error: unknown option `%s`\n", self->argv[0]);
+        argparse_usage(self);
+        exit(1);
+    }
+
+end:
+    memmove(self->out + self->cpidx, self->argv,
+            self->argc * sizeof(*self->out));
+    self->out[self->cpidx + self->argc] = NULL;
+
+    return self->cpidx + self->argc;
+}
+
+void
+argparse_usage(struct argparse *self)
+{
+    if (self->usages) {
+        fprintf(stdout, "Usage: %s\n", *self->usages++);
+        while (*self->usages && **self->usages)
+            fprintf(stdout, "   or: %s\n", *self->usages++);
+    } else {
+        fprintf(stdout, "Usage:\n");
+    }
+
+    // print description
+    if (self->description)
+        fprintf(stdout, "%s\n", self->description);
+
+    fputc('\n', stdout);
+
+    const struct argparse_option *options;
+
+    // figure out best width
+    size_t usage_opts_width = 0;
+    size_t len;
+    options = self->options;
+    for (; options->type != ARGPARSE_OPT_END; options++) {
+        len = 0;
+        if ((options)->short_name) {
+            len += 2;
+        }
+        if ((options)->short_name && (options)->long_name) {
+            len += 2;           // separator ", "
+        }
+        if ((options)->long_name) {
+            len += strlen((options)->long_name) + 2;
+        }
+        if (options->type == ARGPARSE_OPT_INTEGER) {
+            len += strlen("=<int>");
+        }
+        if (options->type == ARGPARSE_OPT_FLOAT) {
+            len += strlen("=<flt>");
+        } else if (options->type == ARGPARSE_OPT_STRING) {
+            len += strlen("=<str>");
+        }
+        len = (len + 3) - ((len + 3) & 3);
+        if (usage_opts_width < len) {
+            usage_opts_width = len;
+        }
+    }
+    usage_opts_width += 4;      // 4 spaces prefix
+
+    options = self->options;
+    for (; options->type != ARGPARSE_OPT_END; options++) {
+        size_t pos = 0;
+        int pad    = 0;
+        if (options->type == ARGPARSE_OPT_GROUP) {
+            fputc('\n', stdout);
+            fprintf(stdout, "%s", options->help);
+            fputc('\n', stdout);
+            continue;
+        }
+        pos = fprintf(stdout, "    ");
+        if (options->short_name) {
+            pos += fprintf(stdout, "-%c", options->short_name);
+        }
+        if (options->long_name && options->short_name) {
+            pos += fprintf(stdout, ", ");
+        }
+        if (options->long_name) {
+            pos += fprintf(stdout, "--%s", options->long_name);
+        }
+        if (options->type == ARGPARSE_OPT_INTEGER) {
+            pos += fprintf(stdout, "=<int>");
+        } else if (options->type == ARGPARSE_OPT_FLOAT) {
+            pos += fprintf(stdout, "=<flt>");
+        } else if (options->type == ARGPARSE_OPT_STRING) {
+            pos += fprintf(stdout, "=<str>");
+        }
+        if (pos <= usage_opts_width) {
+            pad = usage_opts_width - pos;
+        } else {
+            fputc('\n', stdout);
+            pad = usage_opts_width;
+        }
+        fprintf(stdout, "%*s%s\n", pad + 2, "", options->help);
+    }
+
+    // print epilog
+    if (self->epilog)
+        fprintf(stdout, "%s\n", self->epilog);
+}
+
+int
+argparse_help_cb(struct argparse *self, const struct argparse_option *option)
+{
+    (void)option;
+    argparse_usage(self);
+    exit(0);
+}
diff --git a/vendor/argparse.h b/vendor/argparse.h
new file mode 100644
index 0000000..44ce835
--- /dev/null
+++ b/vendor/argparse.h
@@ -0,0 +1,130 @@
+/**
+ * Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
+ * All rights reserved.
+ *
+ * Use of this source code is governed by a MIT-style license that can be found
+ * in the LICENSE file.
+ */
+#ifndef ARGPARSE_H
+#define ARGPARSE_H
+
+/* For c++ compatibility */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+struct argparse;
+struct argparse_option;
+
+typedef int argparse_callback (struct argparse *self,
+                               const struct argparse_option *option);
+
+enum argparse_flag {
+    ARGPARSE_STOP_AT_NON_OPTION = 1,
+};
+
+enum argparse_option_type {
+    /* special */
+    ARGPARSE_OPT_END,
+    ARGPARSE_OPT_GROUP,
+    /* options with no arguments */
+    ARGPARSE_OPT_BOOLEAN,
+    ARGPARSE_OPT_BIT,
+    /* options with arguments (optional or required) */
+    ARGPARSE_OPT_INTEGER,
+    ARGPARSE_OPT_FLOAT,
+    ARGPARSE_OPT_STRING,
+};
+
+enum argparse_option_flags {
+    OPT_NONEG = 1,              /* disable negation */
+};
+
+/**
+ *  argparse option
+ *
+ *  `type`:
+ *    holds the type of the option, you must have an ARGPARSE_OPT_END last in your
+ *    array.
+ *
+ *  `short_name`:
+ *    the character to use as a short option name, '\0' if none.
+ *
+ *  `long_name`:
+ *    the long option name, without the leading dash, NULL if none.
+ *
+ *  `value`:
+ *    stores pointer to the value to be filled.
+ *
+ *  `help`:
+ *    the short help message associated to what the option does.
+ *    Must never be NULL (except for ARGPARSE_OPT_END).
+ *
+ *  `callback`:
+ *    function is called when corresponding argument is parsed.
+ *
+ *  `data`:
+ *    associated data. Callbacks can use it like they want.
+ *
+ *  `flags`:
+ *    option flags.
+ */
+struct argparse_option {
+    enum argparse_option_type type;
+    const char short_name;
+    const char *long_name;
+    void *value;
+    const char *help;
+    argparse_callback *callback;
+    intptr_t data;
+    int flags;
+};
+
+/**
+ * argpparse
+ */
+struct argparse {
+    // user supplied
+    const struct argparse_option *options;
+    const char *const *usages;
+    int flags;
+    const char *description;    // a description after usage
+    const char *epilog;         // a description at the end
+    // internal context
+    int argc;
+    const char **argv;
+    const char **out;
+    int cpidx;
+    const char *optvalue;       // current option value
+};
+
+// built-in callbacks
+int argparse_help_cb(struct argparse *self,
+                     const struct argparse_option *option);
+
+// built-in option macros
+#define OPT_END()        { ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL, 0, 0 }
+#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ }
+#define OPT_BIT(...)     { ARGPARSE_OPT_BIT, __VA_ARGS__ }
+#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ }
+#define OPT_FLOAT(...)   { ARGPARSE_OPT_FLOAT, __VA_ARGS__ }
+#define OPT_STRING(...)  { ARGPARSE_OPT_STRING, __VA_ARGS__ }
+#define OPT_GROUP(h)     { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL, 0, 0 }
+#define OPT_HELP()       OPT_BOOLEAN('h', "help", NULL,                 \
+                                     "show this help message and exit", \
+                                     argparse_help_cb, 0, OPT_NONEG)
+
+int argparse_init(struct argparse *self, struct argparse_option *options,
+                  const char *const *usages, int flags);
+void argparse_describe(struct argparse *self, const char *description,
+                       const char *epilog);
+int argparse_parse(struct argparse *self, int argc, const char **argv);
+void argparse_usage(struct argparse *self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/binn.c b/vendor/binn.c
similarity index 100%
rename from binn.c
rename to vendor/binn.c
diff --git a/include/binn.h b/vendor/binn.h
similarity index 100%
rename from include/binn.h
rename to vendor/binn.h
diff --git a/confini.c b/vendor/confini.c
similarity index 100%
rename from confini.c
rename to vendor/confini.c
diff --git a/include/confini.h b/vendor/confini.h
similarity index 100%
rename from include/confini.h
rename to vendor/confini.h