diff --git a/router/java/src/net/i2p/router/startup/LoadClientAppsJob.java b/router/java/src/net/i2p/router/startup/LoadClientAppsJob.java
new file mode 100644
index 0000000000000000000000000000000000000000..d48d89c1590df8850f168bf572781578b9795528
--- /dev/null
+++ b/router/java/src/net/i2p/router/startup/LoadClientAppsJob.java
@@ -0,0 +1,168 @@
+package net.i2p.router.startup;
+
+import net.i2p.util.I2PThread;
+import net.i2p.util.Log;
+import net.i2p.router.JobImpl;
+import net.i2p.router.RouterContext;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Run any client applications specified in the router.config.  If any clientApp
+ * contains the config property ".onBoot=true" it'll be launched immediately, otherwise
+ * it'll get queued up for starting 2 minutes later.
+ *
+ */
+class LoadClientAppsJob extends JobImpl {
+    private Log _log;
+    /** wait 2 minutes before starting up client apps */
+    private final static long STARTUP_DELAY = 2*60*1000;
+    public LoadClientAppsJob(RouterContext ctx) {
+        super(ctx);
+        _log = ctx.logManager().getLog(LoadClientAppsJob.class);
+    }
+    public void runJob() {
+        int i = 0;
+        while (true) {
+            String className = _context.router().getConfigSetting("clientApp."+i+".main");
+            String clientName = _context.router().getConfigSetting("clientApp."+i+".name");
+            String args = _context.router().getConfigSetting("clientApp."+i+".args");
+            String onBoot = _context.router().getConfigSetting("clientApp." + i + ".onBoot");
+            boolean onStartup = false;
+            if (onBoot != null)
+                onStartup = "true".equals(onBoot) || "yes".equals(onBoot);
+            
+            if (className == null) 
+                break;
+
+            String argVal[] = parseArgs(args);
+            if (onStartup) {
+                // run this guy now
+                runClient(className, clientName, argVal);
+            } else {
+                // wait 2 minutes
+                _context.jobQueue().addJob(new DelayedRunClient(className, clientName, argVal));
+            }
+            i++;
+        }
+    }
+
+    private class DelayedRunClient extends JobImpl {
+        private String _className;
+        private String _clientName;
+        private String _args[];
+        public DelayedRunClient(String className, String clientName, String args[]) {
+            super(LoadClientAppsJob.this._context);
+            _className = className;
+            _clientName = clientName;
+            _args = args;
+            getTiming().setStartAfter(LoadClientAppsJob.this._context.clock().now() + STARTUP_DELAY);
+        }
+        public String getName() { return "Delayed client job"; }
+        public void runJob() {
+            runClient(_className, _clientName, _args);
+        }
+    }
+    
+    static String[] parseArgs(String args) {
+        List argList = new ArrayList(4);
+        if (args != null) {
+            char data[] = args.toCharArray();
+            StringBuffer buf = new StringBuffer(32);
+            boolean isQuoted = false;
+            for (int i = 0; i < data.length; i++) {
+                switch (data[i]) {
+                    case '\'':
+                    case '\"':
+                        if (isQuoted) {
+                            String str = buf.toString().trim();
+                            if (str.length() > 0)
+                                argList.add(str);
+                            buf = new StringBuffer(32);
+                        } else {
+                            isQuoted = true;
+                        }
+                        break;
+                    case ' ':
+                    case '\t':
+                        // whitespace - if we're in a quoted section, keep this as part of the quote,
+                        // otherwise use it as a delim
+                        if (isQuoted) {
+                            buf.append(data[i]);
+                        } else {
+                            String str = buf.toString().trim();
+                            if (str.length() > 0)
+                                argList.add(str);
+                            buf = new StringBuffer(32);
+                        }
+                        break;
+                    default:
+                        buf.append(data[i]);
+                        break;
+                }
+            }
+            if (buf.length() > 0) {
+                String str = buf.toString().trim();
+                if (str.length() > 0)
+                    argList.add(str);
+            }
+        }
+        String rv[] = new String[argList.size()];
+        for (int i = 0; i < argList.size(); i++) 
+            rv[i] = (String)argList.get(i);
+        return rv;
+    }
+
+    private void runClient(String className, String clientName, String args[]) {
+        _log.info("Loading up the client application " + clientName + ": " + className + " " + args);
+        I2PThread t = new I2PThread(new RunApp(className, clientName, args));
+        t.setName(clientName);
+        t.setDaemon(true);
+        t.start();
+    }
+
+    private final class RunApp implements Runnable {
+        private String _className;
+        private String _appName;
+        private String _args[];
+        public RunApp(String className, String appName, String args[]) { 
+            _className = className; 
+            _appName = appName;
+            if (args == null)
+                _args = new String[0];
+            else
+                _args = args;
+        }
+        public void run() {
+            try {
+                Class cls = Class.forName(_className);
+                Method method = cls.getMethod("main", new Class[] { String[].class });
+                method.invoke(cls, new Object[] { _args });
+            } catch (Throwable t) {
+                _log.log(Log.CRIT, "Error starting up the client class " + _className, t);
+            }
+            _log.info("Done running client application " + _appName);
+        }
+    }
+
+    public String getName() { return "Load up any client applications"; }
+    
+    public static void main(String args[]) {
+        test(null);
+        test("hi how are you?");
+        test("hi how are you? ");
+        test(" hi how are you? ");
+        test(" hi how are \"y\"ou? ");
+        test("-nogui -e \"config localhost 17654\" -e \"httpclient 4544\"");
+        test("-nogui -e 'config localhost 17654' -e 'httpclient 4544'");
+    }
+    private static void test(String args) {
+        String parsed[] = parseArgs(args);
+        System.out.print("Parsed [" + args + "] into " + parsed.length + " elements: ");
+        for (int i = 0; i < parsed.length; i++)
+            System.out.print("[" + parsed[i] + "] ");
+        System.out.println();
+    }
+}
diff --git a/router/java/src/net/i2p/router/startup/StartAcceptingClientsJob.java b/router/java/src/net/i2p/router/startup/StartAcceptingClientsJob.java
index 86c51881c64ea8f6db3395730925a58c0104dd3a..2e9e86811c39cafb55f385ceb46f0b2ec1325c0d 100644
--- a/router/java/src/net/i2p/router/startup/StartAcceptingClientsJob.java
+++ b/router/java/src/net/i2p/router/startup/StartAcceptingClientsJob.java
@@ -16,7 +16,6 @@ import net.i2p.router.ClientManagerFacade;
 import net.i2p.router.JobImpl;
 import net.i2p.router.JobQueue;
 import net.i2p.router.Router;
-import net.i2p.router.admin.AdminManager;
 import net.i2p.util.Clock;
 import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
@@ -39,132 +38,6 @@ public class StartAcceptingClientsJob extends JobImpl {
 
         _context.jobQueue().addJob(new ReadConfigJob(_context));
         _context.jobQueue().addJob(new RebuildRouterInfoJob(_context));
-        new AdminManager(_context).startup();
         _context.jobQueue().allowParallelOperation();
-        _context.jobQueue().addJob(new LoadClientAppsJob(_context));
     }
-    
-    public static void main(String args[]) {
-        test(null);
-        test("hi how are you?");
-        test("hi how are you? ");
-        test(" hi how are you? ");
-        test(" hi how are \"y\"ou? ");
-        test("-nogui -e \"config localhost 17654\" -e \"httpclient 4544\"");
-        test("-nogui -e 'config localhost 17654' -e 'httpclient 4544'");
-    }
-    private static void test(String args) {
-        String parsed[] = LoadClientAppsJob.parseArgs(args);
-        System.out.print("Parsed [" + args + "] into " + parsed.length + " elements: ");
-        for (int i = 0; i < parsed.length; i++)
-            System.out.print("[" + parsed[i] + "] ");
-        System.out.println();
-    }
-}
-
-class LoadClientAppsJob extends JobImpl {
-    private Log _log;
-    /** wait 2 minutes before starting up client apps */
-    private final static long STARTUP_DELAY = 2*60*1000;
-    public LoadClientAppsJob(RouterContext ctx) {
-        super(ctx);
-        _log = ctx.logManager().getLog(LoadClientAppsJob.class);
-        getTiming().setStartAfter(STARTUP_DELAY + _context.clock().now());
-    }
-    public void runJob() {
-        int i = 0;
-        while (true) {
-            String className = _context.router().getConfigSetting("clientApp."+i+".main");
-            String clientName = _context.router().getConfigSetting("clientApp."+i+".name");
-            String args = _context.router().getConfigSetting("clientApp."+i+".args");
-            if (className == null) break;
-
-            String argVal[] = parseArgs(args);
-            _log.info("Loading up the client application " + clientName + ": " + className + " " + args);
-            runClient(className, clientName, argVal);
-            i++;
-        }
-    }
-    
-    static String[] parseArgs(String args) {
-        List argList = new ArrayList(4);
-        if (args != null) {
-            char data[] = args.toCharArray();
-            StringBuffer buf = new StringBuffer(32);
-            boolean isQuoted = false;
-            for (int i = 0; i < data.length; i++) {
-                switch (data[i]) {
-                    case '\'':
-                    case '\"':
-                        if (isQuoted) {
-                            String str = buf.toString().trim();
-                            if (str.length() > 0)
-                                argList.add(str);
-                            buf = new StringBuffer(32);
-                        } else {
-                            isQuoted = true;
-                        }
-                        break;
-                    case ' ':
-                    case '\t':
-                        // whitespace - if we're in a quoted section, keep this as part of the quote,
-                        // otherwise use it as a delim
-                        if (isQuoted) {
-                            buf.append(data[i]);
-                        } else {
-                            String str = buf.toString().trim();
-                            if (str.length() > 0)
-                                argList.add(str);
-                            buf = new StringBuffer(32);
-                        }
-                        break;
-                    default:
-                        buf.append(data[i]);
-                        break;
-                }
-            }
-            if (buf.length() > 0) {
-                String str = buf.toString().trim();
-                if (str.length() > 0)
-                    argList.add(str);
-            }
-        }
-        String rv[] = new String[argList.size()];
-        for (int i = 0; i < argList.size(); i++) 
-            rv[i] = (String)argList.get(i);
-        return rv;
-    }
-    
-    private void runClient(String className, String clientName, String args[]) {
-        I2PThread t = new I2PThread(new RunApp(className, clientName, args));
-        t.setName(clientName);
-        t.setDaemon(true);
-        t.start();
-    }
-    
-    private final class RunApp implements Runnable {
-        private String _className;
-        private String _appName;
-        private String _args[];
-        public RunApp(String className, String appName, String args[]) { 
-            _className = className; 
-            _appName = appName;
-            if (args == null)
-                _args = new String[0];
-            else
-                _args = args;
-        }
-        public void run() {
-            try {
-                Class cls = Class.forName(_className);
-                Method method = cls.getMethod("main", new Class[] { String[].class });
-                method.invoke(cls, new Object[] { _args });
-            } catch (Throwable t) {
-                _log.log(Log.CRIT, "Error starting up the client class " + _className, t);
-            }
-            _log.info("Done running client application " + _appName);
-        }
-    }
-    
-    public String getName() { return "Load up any client applications"; }
 }
diff --git a/router/java/src/net/i2p/router/startup/StartupJob.java b/router/java/src/net/i2p/router/startup/StartupJob.java
index 09a10c6343d7728b76c625df108763eec112fc9e..34b0cdc8ce965567ad252698cc912953a0b8689a 100644
--- a/router/java/src/net/i2p/router/startup/StartupJob.java
+++ b/router/java/src/net/i2p/router/startup/StartupJob.java
@@ -12,6 +12,7 @@ package net.i2p.router.startup;
 import net.i2p.router.JobImpl;
 import net.i2p.router.JobQueue;
 import net.i2p.router.StatisticsManager;
+import net.i2p.router.admin.AdminManager;
 import net.i2p.util.Log;
 import net.i2p.router.RouterContext;
 
@@ -35,8 +36,10 @@ public class StartupJob extends JobImpl {
     }
 
     public String getName() { return "Startup Router"; }
-    public void runJob() {
+    public void runJob() {        
         ReadConfigJob.doRead(_context);
+        new AdminManager(_context).startup();
+        _context.jobQueue().addJob(new LoadClientAppsJob(_context));
         _context.statPublisher().startup();
         _context.jobQueue().addJob(new LoadRouterInfoJob(_context));
     }