diff --git a/syndicate-server/protocols/schema-bundle.bin b/syndicate-server/protocols/schema-bundle.bin
index ddff480..86f5d6c 100644
--- a/syndicate-server/protocols/schema-bundle.bin
+++ b/syndicate-server/protocols/schema-bundle.bin
@@ -1,4 +1,5 @@
-´³bundle·µ³
documentation„´³schema·³version°³definitions·³Url´³orµµ±present´³dict·³url´³named³url´³atom³String„„„„„µ±invalid´³dict·³url´³named³url³any„„„„µ±absent´³dict·„„„„„³IOList´³orµµ±bytes´³atom³
+´³bundle·µ³control„´³schema·³version°³definitions·³
+ExitServer´³rec´³lit³exit„´³tupleµ´³named³code´³atom³
SignedInteger„„„„„„³embeddedType€„„µ³
documentation„´³schema·³version°³definitions·³Url´³orµµ±present´³dict·³url´³named³url´³atom³String„„„„„µ±invalid´³dict·³url´³named³url³any„„„„µ±absent´³dict·„„„„„³IOList´³orµµ±bytes´³atom³
 ByteString„„µ±string´³atom³String„„µ±nested´³seqof´³refµ„³IOList„„„„„³Metadata´³rec´³lit³metadata„´³tupleµ´³named³object³any„´³named³info´³dictof´³atom³Symbol„³any„„„„„³Description´³orµµ±present´³dict·³description´³named³description´³refµ„³IOList„„„„„µ±invalid´³dict·³description´³named³description³any„„„„µ±absent´³dict·„„„„„„³embeddedType€„„µ³externalServices„´³schema·³version°³definitions·³Process´³orµµ±simple´³refµ„³CommandLine„„µ±full´³refµ„³FullProcess„„„„³Service´³refµ„³
DaemonService„³ClearEnv´³orµµ±present´³dict·³clearEnv´³named³clearEnv´³atom³Boolean„„„„„µ±invalid´³dict·³clearEnv´³named³clearEnv³any„„„„µ±absent´³dict·„„„„„³EnvValue´³orµµ±set´³atom³String„„µ±remove´³lit€„„µ±invalid³any„„„³Protocol´³orµµ±none´³lit³none„„µ±binarySyndicate´³lit³application/syndicate„„µ±
textSyndicate´³lit³text/syndicate„„„„³
 ProcessDir´³orµµ±present´³dict·³dir´³named³dir´³atom³String„„„„„µ±invalid´³dict·³dir´³named³dir³any„„„„µ±absent´³dict·„„„„„³
 ProcessEnv´³orµµ±present´³dict·³env´³named³env´³dictof´³refµ„³EnvVariable„´³refµ„³EnvValue„„„„„„µ±invalid´³dict·³env´³named³env³any„„„„µ±absent´³dict·„„„„„³CommandLine´³orµµ±shell´³atom³String„„µ±full´³refµ„³FullCommandLine„„„„³EnvVariable´³orµµ±string´³atom³String„„µ±symbol´³atom³Symbol„„µ±invalid³any„„„³FullProcess´³andµ´³dict·³argv´³named³argv´³refµ„³CommandLine„„„„´³named³env´³refµ„³
diff --git a/syndicate-server/protocols/schemas/control.prs b/syndicate-server/protocols/schemas/control.prs
new file mode 100644
index 0000000..fb8c05e
--- /dev/null
+++ b/syndicate-server/protocols/schemas/control.prs
@@ -0,0 +1,12 @@
+version 1 .
+
+# Messages and assertions relating to the `$control` entity enabled in syndicate-server when
+# the `--control` flag is supplied.
+#
+# For example, placing the following into `control-config.pr` and starting the server with
+# `syndicate-server --control -c control-config.pr` will result in the server exiting with
+# exit code 2:
+#
+#     $control ! <exit 2>
+
+ExitServer = <exit @code int> .
diff --git a/syndicate-server/src/main.rs b/syndicate-server/src/main.rs
index 9f68be9..d03ccf0 100644
--- a/syndicate-server/src/main.rs
+++ b/syndicate-server/src/main.rs
@@ -1,5 +1,6 @@
 use preserves_schema::Codec;
 
+use std::convert::TryInto;
 use std::io;
 use std::path::PathBuf;
 use std::sync::Arc;
@@ -61,6 +62,10 @@ struct ServerConfig {
 
     #[structopt(short = "t", long)]
     trace_file: Option<PathBuf>,
+
+    /// Enable `$control` entity.
+    #[structopt(long)]
+    control: bool,
 }
 
 #[tokio::main]
@@ -123,6 +128,20 @@ async fn main() -> ActorResult {
         env.insert("log".to_owned(), AnyValue::domain(Arc::clone(&log_ds)));
         env.insert("gatekeeper".to_owned(), AnyValue::domain(Arc::clone(&gatekeeper)));
 
+        if config.control {
+            env.insert("control".to_owned(), AnyValue::domain(Cap::guard(Language::arc(), t.create(
+                syndicate::entity(())
+                    .on_message(|_, _t, m: crate::schemas::control::ExitServer| {
+                        tracing::info!("$control received exit request with code {}", m.code);
+                        std::process::exit((&m.code).try_into().unwrap_or_else(|_| {
+                            tracing::warn!(
+                                "exit code {} out-of-range of 32-bit signed integer, using 1 instead",
+                                m.code);
+                            1
+                        }))
+                    })))));
+        }
+
         dependencies::boot(t, Arc::clone(&server_config_ds));
         services::config_watcher::on_demand(t, Arc::clone(&server_config_ds));
         services::daemon::on_demand(t, Arc::clone(&server_config_ds), Arc::clone(&log_ds));
