diff --git a/.gitignore b/.gitignore
index 69f851d..aa61156 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 [bB]in/
+.vscode/
\ No newline at end of file
diff --git a/Makefile b/Makefile
index b0f27fd..9756b41 100644
--- a/Makefile
+++ b/Makefile
@@ -6,20 +6,16 @@ CF = -Wall -lkrb5 -lvirt -ljson-c -g
 # ---- ---- #
 
 build: $(shell find . -name "*.c") $(shell find . -name "*.h")
-	@echo "Building sandbox..."
 	@mkdir -p bin
 	@$(CC) $(CF) -o ./bin/sandbox $(shell find . -name "*.c")
 
 run: build
-	@echo "Running sandbox..."
 	@./bin/sandbox
 
 debug: build
-	@echo "Debugging sandbox..."
 	@gdb -q ./bin/sandbox
 
 clean:
-	@echo "Cleaning sandbox..."
 	@rm -rf ./bin
 
 .PHONY: build run clean
diff --git a/src/command.c b/src/command.c
new file mode 100644
index 0000000..ed5688a
--- /dev/null
+++ b/src/command.c
@@ -0,0 +1,93 @@
+#include "command.h"
+
+#include "sandbox.h"
+
+#include <stdio.h>
+#include <string.h>
+
+Command COMMANDS[] = {
+	{"help", "[command]", "Shows help for all or a specific command.", CMD_HELP},
+	{"version", "", "Shows the version of the program.", CMD_VERSION},
+	{NULL},
+	{"add-entry", "<entry> [--root|-r <size>] [--backing|-b <backing>]", "Adds a new entry to the pool", CMD_ADD_ENTRY},
+	{"remove-entry", "<entry>", "Removes an entry from the pool", CMD_REMOVE_ENTRY},
+	{"list-entries", "", "Lists all entries in the pool", CMD_LIST_ENTRIES},
+	{"clear-entries", "", "Clears all entries from the pool", CMD_CLEAR_ENTRIES},
+	{NULL},
+	{"add-backing", "<entry>", "Adds a backing disk to the pool from the given entry", CMD_ADD_BACKING},
+	{"remove-backing", "<backing>", "Removes a backing disk from the pool", CMD_REMOVE_BACKING},
+	{"list-backings", "[--tree|-t]", "Lists all backing disks in the pool", CMD_LIST_BACKINGS},
+	{"clear-backings", "", "Clears all backing disks from the pool", CMD_CLEAR_BACKINGS},
+	{NULL},
+	{"start", "<entry> [--no-pci] [--vnc <port> <password>] [--iso <iso>]", "Starts the sandbox with the given entry", CMD_START},
+	{"power", "", "Sends a power signal to the sandbox", CMD_POWER},
+	{"stop", "[--force|-f] [--timeout|-t <timeout>]", "Stops the sandbox", CMD_STOP},
+	{"status", "", "Shows the status of the sandbox", CMD_STATUS},
+};
+
+Command* find_command(const char* name) {
+	Command* match = NULL;
+
+	// Find all matching commands (starting with the given name)
+	size_t length = strlen(name);
+	for (size_t i = 0; i < sizeof(COMMANDS) / sizeof(COMMANDS[0]); i++) {
+		if (COMMANDS[i].name == NULL)
+			continue;
+
+		// Check the sizes
+		if (strlen(COMMANDS[i].name) < length)
+			continue;
+
+		if (strncmp(name, COMMANDS[i].name, length) == 0) {
+			// Check for multiple matches
+			if (match != NULL)
+				return NULL;
+
+			match = &COMMANDS[i];
+		}
+	}
+
+	return match;
+}
+
+void show_help() {
+	printf("Usage: sandbox <command> [args]\n\n");
+	printf("Commands:\n");
+	for (size_t i = 0; i < sizeof(COMMANDS) / sizeof(COMMANDS[0]); i++) {
+		if (COMMANDS[i].name == NULL) {
+			printf("\n");
+			continue;
+		}
+
+		printf("    %s %s\n", COMMANDS[i].name, COMMANDS[i].args);
+		printf("        %s\n", COMMANDS[i].description);
+	}
+	printf("\n");
+	printf("For more information about a specific command, use 'sandbox help <command>'.\n");
+}
+
+void show_command_help(const Command* command) {
+	printf("Usage: sandbox %s %s\n", command->name, command->args);
+	printf("   %s\n", command->description);
+}
+
+int cmd_help(int argc, char** argv) {
+	if (argc == 0) {
+		show_help();
+		return 0;
+	}
+
+	Command* command = find_command(argv[0]);
+	if (command == NULL) {
+		printf("Unknown command '%s'.\n", argv[0]);
+		return 1;
+	}
+
+	show_command_help(command);
+	return 0;
+}
+
+int cmd_version(int argc, char** argv) {
+	printf("Sandbox version v" SANDBOX_VERSION "\n");
+	return 0;
+}
diff --git a/src/command.h b/src/command.h
new file mode 100644
index 0000000..a164047
--- /dev/null
+++ b/src/command.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <stdlib.h>
+
+typedef enum {
+	CMD_UNKNOWN,
+
+	CMD_HELP,
+	CMD_VERSION,
+
+	CMD_ADD_ENTRY,
+	CMD_REMOVE_ENTRY,
+	CMD_LIST_ENTRIES,
+	CMD_CLEAR_ENTRIES,
+
+	CMD_ADD_BACKING,
+	CMD_REMOVE_BACKING,
+	CMD_LIST_BACKINGS,
+	CMD_CLEAR_BACKINGS,
+
+	CMD_START,
+	CMD_POWER,
+	CMD_STOP,
+	CMD_STATUS,
+} CommandID;
+
+typedef struct {
+	const char* name;
+	const char* args;
+	const char* description;
+	CommandID id;
+} Command;
+
+extern Command COMMANDS[];
+
+/// @brief Finds the best matching command for the given command name.
+/// @param name The name of the command to find.
+/// @return The best matching command or NULL if no or multiple matches were found. No need to free the result.
+Command* find_command(const char* name);
+
+/// @brief Shows the help for all commands.
+void show_help();
+
+/// @brief Shows the help for a specific command.
+/// @param command The command to show the help for.
+void show_command_help(const Command* command);
+
+int cmd_help(int argc, char** argv);
+
+int cmd_version(int argc, char** argv);
\ No newline at end of file
diff --git a/src/sandbox.c b/src/sandbox.c
index 4497949..854fd10 100644
--- a/src/sandbox.c
+++ b/src/sandbox.c
@@ -1,28 +1,34 @@
 #include "sandbox.h"
 
 #include "utils.h"
+#include "command.h"
 
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 int main(int argc, char* argv[]) {
+	if (argc < 2) {
+		show_help();
+		return 0;
+	}
+
+	Command* command = find_command(argv[1]);
+	if (command == NULL) {
+		log_message(LOG_ERROR, "Unknown command '%s'.", argv[1]);
+		return 1;
+	}
+
+	switch (command->id) {
+	case CMD_HELP:
+		return cmd_help(argc - 2, argv + 2);
+	case CMD_VERSION:
+		return cmd_version(argc - 2, argv + 2);
+	default:
+		log_message(LOG_ERROR, "Command '%s' is not implemented.", command->name);
+		break;
+	}
+
 	return 0;
 }
-
-Command* find_command(const char* name) {
-	Command* match = NULL;
-
-	// Find all matching commands (starting with the given name)
-	size_t length = strlen(name);
-	for (size_t i = 0; i < sizeof(COMMANDS) / sizeof(COMMANDS[0]); i++)
-		if (strncmp(name, COMMANDS[i].name, length) == 0) {
-			// Check for multiple matches
-			if (match != NULL)
-				return NULL;
-
-			match = &COMMANDS[i];
-		}
-
-	return match;
-}
diff --git a/src/sandbox.h b/src/sandbox.h
index 9520cbe..cf11893 100644
--- a/src/sandbox.h
+++ b/src/sandbox.h
@@ -2,35 +2,6 @@
 
 #include <stdlib.h>
 
-typedef struct {
-	const char* name;
-	const char* args;
-	const char* description;
-} Command;
-
-Command COMMANDS[] = {
-	{"help", "[command]", "Shows help for all or a specific command."},
-	{"version", NULL, "Shows the version of the program."},
-	{NULL, NULL, NULL},
-	{"add-entry", "<entry> [--root|-r <size>] [--backing|-b <backing>]", "Adds a new entry to the pool"},
-	{"remove-entry", "<entry>", "Removes an entry from the pool"},
-	{"list-entries", NULL, "Lists all entries in the pool"},
-	{"clear-entries", NULL, "Clears all entries from the pool"},
-	{NULL, NULL, NULL},
-	{"add-backing", "<entry>", "Adds a backing disk to the pool from the given entry"},
-	{"remove-backing", "<backing>", "Removes a backing disk from the pool"},
-	{"list-backings", "[--tree|-t]", "Lists all backing disks in the pool"},
-	{"clear-backings", NULL, "Clears all backing disks from the pool"},
-	{NULL, NULL, NULL},
-	{"start", "<entry> [--no-pci] [--vnc <port> <password>] [--iso <iso>]", "Starts the sandbox with the given entry"},
-	{"power", NULL, "Sends a power signal to the sandbox"},
-	{"stop", "[--force|-f] [--timeout|-t <timeout>]", "Stops the sandbox"},
-	{"status", NULL, "Shows the status of the sandbox"},
-};
+#define SANDBOX_VERSION "1.0.0"
 
 int main(int argc, char* argv[]);
-
-/// @brief Finds the best matching command for the given command name.
-/// @param name The name of the command to find.
-/// @return The best matching command or NULL if no or multiple matches were found. No need to free the result.
-Command* find_command(const char* name);