diff --git a/src/kernel_services/plugin_entry_points/db.ml b/src/kernel_services/plugin_entry_points/db.ml
index 8824f51b8b9c3aaaf4878bce0334ccd62b0e5f47..3878bb45f6376a737ff3be5c3030744338358c4c 100644
--- a/src/kernel_services/plugin_entry_points/db.ml
+++ b/src/kernel_services/plugin_entry_points/db.ml
@@ -1077,7 +1077,7 @@ let daemons = ref []
 let on_progress ?(debounced=0) ?on_delayed trigger =
   let d = {
     trigger ;
-    debounced = float debounced /. 1000.0 ;
+    debounced = float debounced *. 0.001 ;
     on_delayed ;
     last_yield_at = 0.0 ;
     next_at = 0.0 ;
@@ -1101,53 +1101,93 @@ let warn_error exn =
 let with_progress ?debounced ?on_delayed trigger job data =
   let d = on_progress ?debounced ?on_delayed trigger in
   let result =
-    try job data with e ->
+    try job data
+    with exn ->
       off_progress d ;
-      raise e
+      raise exn
   in
   off_progress d ; result
 
-(* ---- Yielding ---- *)
+(* ---- Triggering ---- *)
 
 let canceled = ref false
 let cancel () = canceled := true
 
-let yield () =
+let fire ~warn_on_delayed ~forced ~time d =
+  if forced || time > d.next_at then
+    begin
+      try
+        d.next_at <- time +. d.debounced ;
+        d.trigger () ;
+      with
+      | Cancel -> canceled := true
+      | exn -> warn_error exn ; raise exn
+    end ;
+  match d.on_delayed with
+  | None -> ()
+  | Some warn ->
+    if warn_on_delayed && 0.0 < d.last_yield_at then
+      begin
+        let time_since_last_yield = time -. d.last_yield_at in
+        let delay = if d.debounced > 0.0 then d.debounced else 0.1 in
+        if time_since_last_yield > delay then
+          warn (int_of_float (time_since_last_yield *. 1000.0)) ;
+      end ;
+    d.last_yield_at <- time
+
+let raise_if_canceled () =
+  if !canceled then ( canceled := false ; raise Cancel )
+
+(* ---- Yielding ---- *)
+
+let do_yield ~warn_on_delayed ~forced () =
   match !daemons with
   | [] -> ()
   | ds ->
     begin
-      let t = Unix.gettimeofday () in
-      List.iter
-        (fun d ->
-           if t > d.next_at then
-             begin
-               try
-                 d.next_at <- t +. d.debounced ;
-                 d.trigger () ;
-               with
-               | Cancel -> canceled := true
-               | exn -> warn_error exn ; raise exn
-             end ;
-           match d.on_delayed with
-           | None ->
-             ()
-           | Some _ when d.last_yield_at = 0. ->
-             (* first yield *)
-             d.last_yield_at <- t
-           | Some warn ->
-             let time_since_last_yield = t -. d.last_yield_at in
-             let delay = if d.debounced > 0.0 then d.debounced else 0.1 in
-             if time_since_last_yield > delay then
-               warn (int_of_float (time_since_last_yield *. 1000.0)) ;
-             d.last_yield_at <- t)
-        ds;
-      if !canceled then ( canceled := false ; raise Cancel )
+      let time = Unix.gettimeofday () in
+      List.iter (fire ~warn_on_delayed ~forced ~time) ds ;
+      raise_if_canceled () ;
     end
 
-let flush () =
-  List.iter (fun d -> d.next_at <- 0.0) !daemons ;
-  yield ()
+let yield = do_yield ~warn_on_delayed:true ~forced:false
+let flush = do_yield ~warn_on_delayed:false ~forced:true
+
+(* ---- Sleeping ---- *)
+
+let rec gcd a b = if b = 0 then a else gcd b (a mod b)
+
+(* n=0 means no periodic daemons (yet) *)
+let merge_period n { debounced = p } =
+  if p > 0.0 then gcd (int_of_float (p *. 1000.0)) n else n
+
+let sleep ms =
+  if ms > 0 then
+    let delta = float ms *. 0.001 in
+    let period = List.fold_left merge_period 0 !daemons in
+    if period = 0 then
+      begin
+        Unix.sleepf delta ;
+        do_yield ~warn_on_delayed:false ~forced:false ()
+      end
+    else
+      let delay = float period *. 0.001 in
+      let finished_at = Unix.gettimeofday () +. delta in
+      let rec wait_and_trigger () =
+        Unix.sleepf delay ;
+        let time = Unix.gettimeofday () in
+        List.iter
+          (fire ~warn_on_delayed:false ~forced:false ~time)
+          !daemons ;
+        raise_if_canceled () ;
+        if time < finished_at then
+          if time +. delay > finished_at then
+            Unix.sleepf (finished_at -. time)
+          else wait_and_trigger ()
+      in
+      wait_and_trigger ()
+
+(* ---- Deprecated old API ---- *)
 
 let progress = ref (Kernel.deprecated "!Db.progress()" ~now:"Db.yield()" yield)
 
diff --git a/src/kernel_services/plugin_entry_points/db.mli b/src/kernel_services/plugin_entry_points/db.mli
index 02f3e32ba3d2f081f9416489228b92ec387cb6e0..85362586ac31164101ffc05a44234e2ad8afab16 100644
--- a/src/kernel_services/plugin_entry_points/db.mli
+++ b/src/kernel_services/plugin_entry_points/db.mli
@@ -1339,18 +1339,18 @@ module Derefs : INOUT with type t = Locations.Zone.t
     @plugin development guide
     @deprecated Frama-C+dev *)
 val progress: (unit -> unit) ref
+[@@ deprecated "Use Db.yield instead."]
 
 (** Registered daemon on progress. *)
 type daemon
 
 (**
-
    [on_progress ?debounced ?on_delayed trigger] registers [trigger] as new
-   daemon to be executed on each [yield].
-   @param debounced the least amount of time, in milliseconds, between two
-   successive calls to the daemon (default is 0ms).
+   daemon to be executed on each {!yield}.
+   @param debounced the least amount of time between two successive calls to the
+   daemon, in milliseconds (default is 0ms).
    @param on_delayed the callback invoked as soon as the time since the last
-   [yield] is greater than [debounced] milliseconds (or 100ms at least).
+   {!yield} is greater than [debounced] milliseconds (or 100ms at least).
 *)
 val on_progress :
   ?debounced:int -> ?on_delayed:(int -> unit) -> (unit -> unit) -> daemon
@@ -1361,11 +1361,13 @@ val off_progress : daemon -> unit
 (** Trigger all daemons immediately. *)
 val flush : unit -> unit
 
-(** Trigger all registered daemons (debounced). *)
+(** Trigger all registered daemons (debounced).
+    This function should be called from time to time by all analysers taking
+    time. In GUI mode, this will make the interface reactive. *)
 val yield : unit -> unit
 
-(** Interrupt the currently running job.
-    The next call to [Db.yield()] will raise a [Cancel] exception. *)
+(** Interrupt the currently running job at the next call to {!yield} as a
+    [Cancel] exception is raised. *)
 val cancel : unit -> unit
 
 (**
@@ -1389,17 +1391,22 @@ val cancel : unit -> unit
        notes    :      (1)           (2)           (3)
    ]}
 
-   1. First yield, normal trigger.
-
-   2. Debounced yields leads to this second trigger.
-
-   3. Delayed warning invoked since there was no yield for more than debounced period.
+   {ol {li First yield, normal trigger.}
+   {li Debounced yields leads to this second trigger.}
+   {li Delayed warning invoked since there was no yield for more than debounced period.}}
 *)
 val with_progress :
   ?debounced:int -> ?on_delayed:(int -> unit) ->
   (unit -> unit) -> ('a -> 'b) -> 'a -> 'b
 
-(** This exception may be raised by {!progress} to interrupt computations. *)
+(**
+   Pauses the currently running process for the specified time, in milliseconds.
+   Registered daemons, if any, will be regularly triggered during this waiting
+   time at a reasonable period with respect to their debouncing constraints.
+*)
+val sleep : int -> unit
+
+(** This exception may be raised by {!yield} to interrupt computations. *)
 exception Cancel
 
 (*
diff --git a/src/plugins/server/kernel_main.ml b/src/plugins/server/kernel_main.ml
index af05488f599dbeb746a800ba05315730341010c6..4161d4533e2c87ac43997725e716c37fbaccca77 100644
--- a/src/plugins/server/kernel_main.ml
+++ b/src/plugins/server/kernel_main.ml
@@ -185,27 +185,28 @@ let monitoring = ref false
 let monitored = ref false
 let events : Log.event Queue.t = Queue.create ()
 
-let monitor flag =
+let set_monitoring flag =
   if flag != !monitoring then
-    ( if flag then
-        Senv.feedback "Start logs monitoring."
-      else
-        Senv.feedback "Stop logs monitoring." ) ;
-  monitoring := flag ;
+    monitoring := flag ;
   if !monitoring && not !monitored then
     begin
       monitored := true ;
       Log.add_listener (fun evt -> if !monitoring then Queue.add evt events)
     end
 
-let monitor_logs () = monitor (Senv.Log.get ())
-
 let monitor_server activity =
-  if activity then monitor true else monitor_logs ()
+  if not (Senv.AutoLog.get ()) then set_monitoring activity
+
+let monitor_autologs () =
+  if Senv.AutoLog.get () then
+    begin
+      Senv.feedback "Auto-log started." ;
+      set_monitoring true ;
+    end
 
 let () =
   Main.on monitor_server ;
-  Cmdline.run_after_configuring_stage monitor_logs
+  Cmdline.run_after_configuring_stage monitor_autologs
 
 (* -------------------------------------------------------------------------- *)
 (* --- Log Requests                                                       --- *)
@@ -214,7 +215,8 @@ let () =
 let () = Request.register
     ~page ~kind:`SET ~name:"kernel.setLogs"
     ~descr:(Md.plain "Turn logs monitoring on/off")
-    ~input:(module Jbool) ~output:(module Junit) monitor
+    ~input:(module Jbool) ~output:(module Junit)
+    set_monitoring
 
 let () = Request.register
     ~page ~kind:`GET ~name:"kernel.getLogs"
diff --git a/src/plugins/server/main.ml b/src/plugins/server/main.ml
index c628ffc4c34e7ec16a7d25382b15ac7660f02130..fc42c15e056be1317b6ed6add87a493eb60e691f 100644
--- a/src/plugins/server/main.ml
+++ b/src/plugins/server/main.ml
@@ -26,7 +26,6 @@
 
 module Senv = Server_parameters
 
-let option f = function None -> () | Some x -> f x
 
 (* -------------------------------------------------------------------------- *)
 (* --- Registry                                                           --- *)
@@ -77,7 +76,7 @@ type 'a message = {
 
 (* Private API: *)
 
-type 'a exec = {
+type 'a process = {
   id : 'a ;
   request : string ;
   data : json ;
@@ -87,14 +86,15 @@ type 'a exec = {
 }
 
 type 'a server = {
-  yield : int ;
+  polling : int ;
   pretty : Format.formatter -> 'a -> unit ;
   equal : 'a -> 'a -> bool ;
   fetch : unit -> 'a message option ;
-  q_in : 'a exec Queue.t ;
+  q_in : 'a process Queue.t ;
   q_out : 'a response Stack.t ;
+  mutable daemon : Db.daemon option ;
   mutable shutdown : bool ;
-  mutable running : 'a exec option ;
+  mutable running : 'a process option ;
 }
 
 exception Killed
@@ -115,6 +115,9 @@ let pp_request pp fmt (r : _ request) =
     else
       Format.fprintf fmt "Request %s:%a" request pp id
 
+let pp_process pp fmt (p : _ process) =
+  Format.fprintf fmt "Execute %s:%a" p.request pp p.id
+
 let pp_response pp fmt (r : _ response) =
   match r with
   | `Error(id,err) -> Format.fprintf fmt "Error %a: %s" pp id err
@@ -131,31 +134,35 @@ let pp_response pp fmt (r : _ response) =
 (* --- Request Handling                                                   --- *)
 (* -------------------------------------------------------------------------- *)
 
-let execute exec : _ response =
+let run proc : _ response =
   try
-    let data = exec.handler exec.data in
-    `Data(exec.id,data)
+    let data = proc.handler proc.data in
+    `Data(proc.id,data)
   with
-  | Killed -> `Killed exec.id
-  | Data.InputError msg -> `Error(exec.id,msg)
+  | Killed -> `Killed proc.id
+  | Data.InputError msg -> `Error(proc.id,msg)
   | Sys.Break as exn -> raise exn (* Silently pass the exception *)
   | exn when Cmdline.catch_at_toplevel exn ->
     Senv.warning "[%s] Uncaught exception:@\n%s"
-      exec.request (Cmdline.protect exn) ;
-    `Error(exec.id,Printexc.to_string exn)
-
-let execute_debug server yield exec =
-  let on_delayed =
-    if Senv.debug_atleast 1 then
-      (Senv.debug "Trigger %s:%a" exec.request server.pretty exec.id ;
-       Some (fun delay -> Senv.debug
-                "No yield since %dms during %s" delay exec.request))
-    else None
-  in Db.with_progress ~debounced:server.yield ?on_delayed yield execute exec
-
-let reply_debug server resp =
+      proc.request (Cmdline.protect exn) ;
+    `Error(proc.id,Printexc.to_string exn)
+
+let delayed process =
   if Senv.debug_atleast 1 then
-    Senv.debug "%a" (pp_response server.pretty) resp ;
+    Some (fun d -> Senv.debug "No yield since %dms during %s" d process)
+  else None
+
+let execute server ?yield proc =
+  Senv.debug "%a" (pp_process server.pretty) proc ;
+  let resp = match yield with
+    | Some yield when proc.yield ->
+      Db.with_progress
+        ~debounced:server.polling
+        ?on_delayed:(delayed proc.request)
+        yield run proc
+    | _ -> run proc
+  in
+  Senv.debug "%a" (pp_response server.pretty) resp ;
   Stack.push resp server.q_out
 
 (* -------------------------------------------------------------------------- *)
@@ -173,33 +180,35 @@ let process_request (server : 'a server) (request : 'a request) : unit =
   | `Poll -> ()
   | `Shutdown ->
     begin
-      option kill_exec server.running ;
+      Extlib.may kill_exec server.running ;
       Queue.clear server.q_in ;
       Stack.clear server.q_out ;
       server.shutdown <- true ;
     end
   | `Kill id ->
     begin
-      let kill = kill_request server.equal id in
-      Queue.iter kill server.q_in ;
-      option kill server.running ;
+      let set_killed = kill_request server.equal id in
+      Queue.iter set_killed server.q_in ;
+      Extlib.may set_killed server.running ;
     end
   | `Request(id,request,data) ->
     begin
       match find request with
-      | None -> reply_debug server (`Rejected id)
+      | None ->
+        Senv.debug "Rejected %a" server.pretty id ;
+        Stack.push (`Rejected id) server.q_out
       | Some( `GET , handler ) ->
-        let exec = { id ; request ; handler ; data ;
+        let proc = { id ; request ; handler ; data ;
                      yield = false ; killed = false } in
-        reply_debug server (execute exec)
+        execute server proc ;
       | Some( `SET , handler ) ->
-        let exec = { id ; request ; handler ; data ;
+        let proc = { id ; request ; handler ; data ;
                      yield = false ; killed = false } in
-        Queue.push exec server.q_in
+        Queue.push proc server.q_in
       | Some( `EXEC , handler ) ->
-        let exec = { id ; request ; handler ; data ;
+        let proc = { id ; request ; handler ; data ;
                      yield = true ; killed = false } in
-        Queue.push exec server.q_in
+        Queue.push proc server.q_in
     end
 
 (* -------------------------------------------------------------------------- *)
@@ -217,35 +226,28 @@ let communicate server =
     Stack.iter (fun r -> pool := r :: !pool) server.q_out ;
     Stack.clear server.q_out ;
     message.callback !pool ;
-    option raise error ; true
+    Extlib.may raise error ; true
 
 (* -------------------------------------------------------------------------- *)
 (* --- Yielding                                                           --- *)
 (* -------------------------------------------------------------------------- *)
 
 let do_yield server () =
-  begin
-    option raise_if_killed server.running ;
-    ignore ( communicate server );
-  end
+  Extlib.may raise_if_killed server.running ;
+  ignore ( communicate server )
 
 (* -------------------------------------------------------------------------- *)
 (* --- One Step Process                                                   --- *)
 (* -------------------------------------------------------------------------- *)
 
-let rec fetch_exec q =
-  if Queue.is_empty q then None
-  else
-    let e = Queue.pop q in
-    if e.killed then fetch_exec q else Some e
-
 let process server =
-  match fetch_exec server.q_in with
-  | None -> communicate server
-  | Some exec ->
-    server.running <- Some exec ;
+  if Queue.is_empty server.q_in then
+    communicate server
+  else
+    let proc = Queue.pop server.q_in in
+    server.running <- Some proc ;
     try
-      reply_debug server (execute_debug server (do_yield server) exec) ;
+      execute server ~yield:(do_yield server) proc ;
       server.running <- None ;
       true
     with exn ->
@@ -260,42 +262,89 @@ let in_range ~min:a ~max:b v = min (max a v) b
 
 let kill () = raise Killed
 
-let demons = ref []
-let on callback = demons := !demons @ [ callback ]
+let daemons = ref []
+let on callback = daemons := !daemons @ [ callback ]
 let signal activity =
-  List.iter (fun f -> try f activity with _ -> ()) !demons
-
-let run ~pretty ?(equal=(=)) ~fetch () =
-  begin
-    let yield = in_range ~min:1 ~max:200 (Senv.Yield.get ()) in
-    let idle_ms = in_range ~min:1 ~max:2000 (Senv.Idle.get ()) in
-    let idle = float_of_int idle_ms /. 1000.0 in
-    let server = {
-      fetch ; yield ; equal ; pretty ;
-      q_in = Queue.create () ;
-      q_out = Stack.create () ;
-      running = None ;
-      shutdown = false ;
-    } in
-    try
-      (* TODO: remove the following line once the Why3 signal handler is not
-         used anymore. *)
-      Sys.catch_break true;
+  List.iter (fun f -> try f activity with _ -> ()) !daemons
+
+let create ~pretty ?(equal=(=)) ~fetch () =
+  let polling = in_range ~min:1 ~max:200 (Senv.Polling.get ()) in
+  {
+    fetch ; polling ; equal ; pretty ;
+    q_in = Queue.create () ;
+    q_out = Stack.create () ;
+    daemon = None ;
+    running = None ;
+    shutdown = false ;
+  }
+
+(* -------------------------------------------------------------------------- *)
+(* --- Start / Stop                                                       --- *)
+(* -------------------------------------------------------------------------- *)
+
+let start server =
+  match server.daemon with
+  | Some _ -> ()
+  | None ->
+    begin
+      Senv.feedback "Server enabled." ;
+      let daemon =
+        Db.on_progress
+          ~debounced:server.polling
+          ?on_delayed:(delayed "command line")
+          (do_yield server)
+      in
+      server.daemon <- Some daemon ;
       signal true ;
-      Senv.feedback "Server running." ;
-      begin try
-          while not server.shutdown do
-            let activity = process server in
-            if not activity then Unix.sleepf idle ;
-          done ;
-        with Sys.Break -> () (* Ctr+C, just leave the loop normally *)
-      end;
-      Senv.feedback "Server shutdown." ;
-      signal false ;
-    with exn ->
-      Senv.feedback "Server interruped (fatal error)." ;
+    end
+
+let stop server =
+  match server.daemon with
+  | None -> ()
+  | Some daemon ->
+    begin
+      Senv.feedback "Server disabled." ;
+      server.daemon <- None ;
+      Db.off_progress daemon ;
       signal false ;
-      raise exn
-  end
+    end
+
+let foreground server =
+  match server.daemon with
+  | None -> ()
+  | Some daemon ->
+    begin
+      server.daemon <- None ;
+      Db.off_progress daemon ;
+    end
+
+(* -------------------------------------------------------------------------- *)
+(* --- Main Loop                                                          --- *)
+(* -------------------------------------------------------------------------- *)
+
+let run server =
+  try
+    ( (* TODO: catch-break to be removed once Why3 signal handler is fixed *)
+      Sys.catch_break true
+    ) ;
+    Senv.feedback "Server running." ;
+    foreground server ;
+    signal true ;
+    begin
+      try
+        while not server.shutdown do
+          let activity = process server in
+          if not activity then Db.sleep server.polling
+        done ;
+      with Sys.Break -> () (* Ctr+C, just leave the loop normally *)
+    end;
+    Senv.feedback "Server shutdown." ;
+    signal false ;
+  with
+  | Killed -> ()
+  | exn ->
+    Senv.feedback "Server interruped (fatal error)." ;
+    signal false ;
+    raise exn
 
 (* -------------------------------------------------------------------------- *)
diff --git a/src/plugins/server/main.mli b/src/plugins/server/main.mli
index 75d51a0d17af477241683a5ccdc2c5915210dfe3..acd7ef46c6b7030dc51c34cc2b0c187852f00768 100644
--- a/src/plugins/server/main.mli
+++ b/src/plugins/server/main.mli
@@ -66,6 +66,8 @@ type 'a message = {
   callback : 'a response list -> unit ;
 }
 
+type 'a server
+
 (**
    Run a server with the provided low-level network primitives to
    actually exchange data.
@@ -75,11 +77,25 @@ type 'a message = {
 
    Default equality is the standard `(=)` one.
 *)
-val run :
+val create :
   pretty:(Format.formatter -> 'a -> unit) ->
   ?equal:('a -> 'a -> bool) ->
   fetch:(unit -> 'a message option) ->
-  unit -> unit
+  unit -> 'a server
+
+(** Run the server forever.
+    The function will not return until the server is shut down. *)
+val run : 'a server -> unit
+
+(** Start the server in background.
+    The function returns immediately
+    after installing a daemon that accepts GET requests received by
+    the server on calls to `Db.yield()`.
+*)
+val start : 'a server -> unit
+
+(** Stop the server if it is running in background. *)
+val stop : 'a server -> unit
 
 (** Kills the currently running request. Actually raises an exception. *)
 val kill : unit -> 'a
diff --git a/src/plugins/server/server_parameters.ml b/src/plugins/server/server_parameters.ml
index 57dbdd133f9f088015fe82df6ea19932565b883f..5b9e0018622e06add5fcf012e2bdc76d0d0d92cc 100644
--- a/src/plugins/server/server_parameters.ml
+++ b/src/plugins/server/server_parameters.ml
@@ -33,22 +33,33 @@ module P = Plugin.Register
 
 include P
 
-module Idle = P.Int
+(* -------------------------------------------------------------------------- *)
+(* --- Server General Options                                             --- *)
+(* -------------------------------------------------------------------------- *)
+
+module Polling = P.Int
     (struct
-      let option_name = "-server-idle"
+      let option_name = "-server-polling"
       let arg_name = "ms"
-      let default = 20
-      let help = "Waiting time (in milliseconds) when idle"
+      let default = 50
+      let help = "Server polling time period, in milliseconds (default 50ms)"
     end)
 
-module Yield = P.Int
+module AutoLog = P.False
     (struct
-      let option_name = "-server-yield"
-      let arg_name = "ms"
-      let default = 20
-      let help = "Yielding time (in milliseconds) during computations"
+      let option_name = "-server-auto-log"
+      let help =
+        "Start monitoring logs before server is running (default is false)"
     end)
 
+(* -------------------------------------------------------------------------- *)
+(* --- Doc Options                                                        --- *)
+(* -------------------------------------------------------------------------- *)
+
+let server_doc = add_group "Server Doc Generation"
+let () = Parameter_customize.set_group server_doc
+let () = Parameter_customize.do_not_save ()
+
 module Doc = P.String
     (struct
       let option_name = "-server-doc"
@@ -57,12 +68,6 @@ module Doc = P.String
       let help = "Output a markdown documentation of the server in <dir>"
     end)
 
-module Log = P.False
-    (struct
-      let option_name = "-server-logs"
-      let help = "Start (or stop) monitoring logs"
-    end)
-
 let wpage = register_warn_category "inconsistent-page"
 let wkind = register_warn_category "inconsistent-kind"
 let wname = register_warn_category "invalid-name"
diff --git a/src/plugins/server/server_parameters.mli b/src/plugins/server/server_parameters.mli
index 9bbd8a148fde84d797559b9675f44098c42e59c7..33406edeb1db315f587b0a26ec136b006c6af303 100644
--- a/src/plugins/server/server_parameters.mli
+++ b/src/plugins/server/server_parameters.mli
@@ -24,10 +24,9 @@
 
 include Plugin.General_services
 
-module Idle : Parameter_sig.Int (** Idle waiting time (in ms) *)
-module Yield : Parameter_sig.Int (** Yield time (in ms) *)
 module Doc : Parameter_sig.String (** Generate documentation *)
-module Log : Parameter_sig.Bool (** Monitor logs *)
+module Polling : Parameter_sig.Int (** Idle waiting time (in ms) *)
+module AutoLog : Parameter_sig.Bool (** Monitor logs *)
 
 val wpage : warn_category (** Inconsistent page warning *)
 val wkind : warn_category (** Inconsistent category warning *)
diff --git a/src/plugins/server/server_zmq.ml b/src/plugins/server/server_zmq.ml
index 82d2ce4316762eb1f638f499c928eb15000d2442..b9bc13013539919685dfac227d8039d37869180e 100644
--- a/src/plugins/server/server_zmq.ml
+++ b/src/plugins/server/server_zmq.ml
@@ -32,12 +32,30 @@ module Senv = Server_parameters
 let zmq_group = Senv.add_group "Protocol ZeroMQ"
 
 let () = Parameter_customize.set_group zmq_group
-module Enabled = Senv.String
+module Socket = Senv.String
     (struct
       let option_name = "-server-zmq"
       let arg_name = "url"
       let default = ""
-      let help = "Establish a ZeroMQ server and listen for connections"
+      let help =
+        "Launch the ZeroMQ server (in background).\n\
+         The server can handle GET requests during the\n\
+         execution of the frama-c command line.\n\
+         Finally, the server is executed until shutdown."
+    end)
+
+let () = Parameter_customize.set_group zmq_group
+module Client = Senv.String
+    (struct
+      let option_name = "-server-gui"
+      let arg_name = "cmd"
+      let default = ""
+      let help =
+        "Launch the ZeroMQ client (as a child process).\n\
+         If not started by -server-zmq <url>, the ZeroMQ server\n\
+         is established with a local 'ipc://<tmp>' address.\n\
+         The specified <cmd> is passed the actual server <url>\n\
+         as first and unique argument."
     end)
 
 let _ = Doc.page `Protocol ~title:"ZeroMQ Protocol" ~filename:"server_zmq.md"
@@ -46,14 +64,14 @@ let _ = Doc.page `Protocol ~title:"ZeroMQ Protocol" ~filename:"server_zmq.md"
 (* --- ZMQ Context                                                        --- *)
 (* -------------------------------------------------------------------------- *)
 
-let context =
+let zmq_context =
   let zmq = ref None in
   fun () ->
     match !zmq with
     | Some ctxt -> ctxt
     | None ->
       let major,minor,patch = Zmq.version () in
-      Senv.feedback "ZeroMQ %d.%d.%d" major minor patch ;
+      Senv.debug "ZeroMQ [v%d.%d.%d]" major minor patch ;
       let ctxt = Zmq.Context.create () in
       at_exit (fun () -> Zmq.Context.terminate ctxt) ;
       zmq := Some ctxt ; ctxt
@@ -117,25 +135,78 @@ let fetch socket () =
 (* --- Establish the Server                                               --- *)
 (* -------------------------------------------------------------------------- *)
 
-let establish url =
-  if url <> "" then
-    begin
-      let context = context () in
-      let socket = Zmq.Socket.(create context rep) in
-      try
-        Zmq.Socket.bind socket url ;
-        Senv.feedback "ZeroMQ [%s]" url ;
-        Main.run ~pretty:Format.pp_print_string ~fetch:(fetch socket) () ;
-        Zmq.Socket.close socket ;
-      with exn ->
+let pretty = Format.pp_print_string
+let server = ref None
+let client = ref None
+
+let ping () =
+  match !client with None -> None | Some process ->
+  try Some (process ())
+  with Unix.Unix_error _ -> None
+
+let launch_server url =
+  match !server with
+  | Some _ -> ()
+  | None ->
+    let context = zmq_context () in
+    let socket = Zmq.Socket.(create context rep) in
+    try
+      Zmq.Socket.bind socket url ;
+      Senv.debug "ZeroMQ [%s]" url ;
+      let srv = Main.create ~pretty ~fetch:(fetch socket) () in
+      server := Some(url,srv) ;
+      Extlib.safe_at_exit begin fun () ->
+        Main.stop srv ;
         Zmq.Socket.close socket ;
-        raise exn
+        server := None ;
+      end ;
+      Main.start srv ;
+      Cmdline.at_normal_exit (fun () -> Main.run srv) ;
+    with exn ->
+      Zmq.Socket.close socket ;
+      raise exn
+
+let temp_url () =
+  let socket = Filename.temp_file "frama-c.socket" ".io" in
+  Extlib.safe_at_exit (fun () -> Extlib.safe_remove socket) ;
+  "ipc://" ^ socket
+
+let start_server () =
+  match !server with
+  | None ->
+    let socket = Socket.get () in
+    let url = if socket = "" then temp_url () else socket in
+    launch_server url ; url
+  | Some (url,_) -> url
+
+let launch_client cmd =
+  match !client with
+  | Some _ -> ()
+  | None ->
+    begin
+      let url = start_server () in
+      let process = Command.command_async cmd [| url |] in
+      Senv.debug "%s --connect %s@." cmd url ;
+      Senv.feedback "Client launched." ;
+      client := Some process ;
+      Extlib.safe_at_exit
+        begin fun () ->
+          match ping () with
+          | Some (Not_ready kill) ->
+            Senv.feedback "Client interrupted." ;
+            kill ()
+          | _ -> ()
+        end ;
     end
 
-(* -------------------------------------------------------------------------- *)
-(* --- Establish the Server from Command line                             --- *)
-(* -------------------------------------------------------------------------- *)
+let cmdline () =
+  begin
+    let url = Socket.get () in
+    if url <> "" then launch_server url ;
+    let cmd = Client.get () in
+    if cmd <> "" then launch_client cmd ;
+  end
 
-let () = Db.Main.extend (fun () -> establish (Enabled.get ()))
+let () = Db.Main.extend cmdline
 
 (* -------------------------------------------------------------------------- *)