diff --git a/Nibriboard/Nibriboard.csproj b/Nibriboard/Nibriboard.csproj
index 66807bd..aa3591a 100644
--- a/Nibriboard/Nibriboard.csproj
+++ b/Nibriboard/Nibriboard.csproj
@@ -54,7 +54,7 @@
       <HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
     </Reference>
     <Reference Include="SharpCompress">
-      <HintPath>..\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll</HintPath>
+      <HintPath>..\packages\SharpCompress.0.18.0\lib\net45\SharpCompress.dll</HintPath>
     </Reference>
   </ItemGroup>
   <ItemGroup>
diff --git a/Nibriboard/NibriboardServer.cs b/Nibriboard/NibriboardServer.cs
index c599a48..3dfd048 100644
--- a/Nibriboard/NibriboardServer.cs
+++ b/Nibriboard/NibriboardServer.cs
@@ -1,12 +1,15 @@
 ﻿using System;
 using System.Threading.Tasks;
+using System.Threading;
 
 using IotWeb.Server;
 using IotWeb.Common.Http;
 
 using Nibriboard.RippleSpace;
 using Nibriboard.Client;
-using System.Threading;
+using System.Net.Sockets;
+using System.Net;
+using System.IO;
 
 namespace Nibriboard
 {
@@ -16,6 +19,7 @@ namespace Nibriboard
 	/// </summary>
 	public class NibriboardServer
 	{
+		private TcpListener commandServer;
 		private HttpServer httpServer;
 
 		private ClientSettings clientSettings;
@@ -24,6 +28,7 @@ namespace Nibriboard
 		private readonly CancellationTokenSource clientManagerCanceller = new CancellationTokenSource();
 		private NibriClientManager clientManager;
 
+		public readonly int CommandPort = 31587;
 		public readonly int Port = 31586;
 
 		public NibriboardServer(int inPort = 31586)
@@ -73,5 +78,52 @@ namespace Nibriboard
 
 			await planeManager.StartMaintenanceMonkey();
 		}
+
+		/// <summary>
+		/// Starts the command listener.
+		/// The command listener is a light tcp-based command console that allows control
+		/// of the Nibriboard server, since C# doesn't currently have support for signal handling.
+		/// It listeners on [::1] _only_, to avoid security issues.
+		/// In the future, a simple secret might be required to use it to aid security further.
+		/// </summary>
+		public async Task StartCommandListener()
+		{
+			commandServer = new TcpListener(IPAddress.IPv6Loopback, CommandPort);
+			commandServer.Start();
+			Log.WriteLine("[CommandConsole] Listening on {0}.", new IPEndPoint(IPAddress.IPv6Loopback, CommandPort));
+			while(true)
+			{
+				TcpClient nextClient = await commandServer.AcceptTcpClientAsync();
+
+				StreamReader source = new StreamReader(nextClient.GetStream());
+				StreamWriter destination = new StreamWriter(nextClient.GetStream()) { AutoFlush = true };
+
+				string rawCommand = await source.ReadLineAsync();
+				string[] commandParts = rawCommand.Split(" \t".ToCharArray());
+				Console.WriteLine("[CommandConsole] Client executing {0}", rawCommand);
+
+				try
+				{
+					switch(commandParts[0].Trim())
+					{
+						case "help":
+							await destination.WriteLineAsync("NibriboardServer Command Console");
+							await destination.WriteLineAsync("================================");
+							await destination.WriteLineAsync("Available commands:");
+							await destination.WriteLineAsync("    help     Show this message");
+							await destination.WriteLineAsync("    save     Save the ripplespace to disk");
+							break;
+						case "save":
+							await planeManager.Save();
+							break;
+					}
+				}
+				catch(Exception error)
+				{
+					await destination.WriteLineAsync(error.ToString());
+				}
+				nextClient.Close();
+			}
+		}
 	}
 }
diff --git a/Nibriboard/Program.cs b/Nibriboard/Program.cs
index 857e1c3..4289b4d 100644
--- a/Nibriboard/Program.cs
+++ b/Nibriboard/Program.cs
@@ -16,7 +16,8 @@ namespace Nibriboard
 
 			NibriboardServer server = new NibriboardServer();
 			Task.WaitAll(
-				server.Start()
+				server.Start(),
+				server.StartCommandListener()
 			);
 		}
 	}
diff --git a/Nibriboard/RippleSpace/RippleSpaceManager.cs b/Nibriboard/RippleSpace/RippleSpaceManager.cs
index f3163f5..249bd5f 100644
--- a/Nibriboard/RippleSpace/RippleSpaceManager.cs
+++ b/Nibriboard/RippleSpace/RippleSpaceManager.cs
@@ -108,6 +108,11 @@ namespace Nibriboard.RippleSpace
 
 		}
 
+		public async Task Save()
+		{
+			throw new NotImplementedException();
+		}
+
 		public async Task<RippleSpaceManager> FromFile(string filename)
 		{
 			if(!File.Exists(filename))
diff --git a/Nibriboard/packages.config b/Nibriboard/packages.config
index 8c0a927..fe4c40b 100644
--- a/Nibriboard/packages.config
+++ b/Nibriboard/packages.config
@@ -3,5 +3,5 @@
   <package id="IotWeb" version="0.8.6" targetFramework="net452" />
   <package id="MimeSharp" version="1.0.0" targetFramework="net45" />
   <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
-  <package id="SharpCompress" version="0.17.1" targetFramework="net461" />
+  <package id="SharpCompress" version="0.18.0" targetFramework="net461" />
 </packages>
\ No newline at end of file
