diff --git a/.env.sample b/.env.sample
index 5afdcbf8..d0092bd7 100644
--- a/.env.sample
+++ b/.env.sample
@@ -11,3 +11,13 @@ GITHUB_WEBHOOK_SECRET=MUST_BE_CONFIGURED
# For example write blahblahblah here, if you want for this bot to
# respond to @blahblahblah claim.
# TRIAGEBOT_USERNAME=CAN_BE_CONFIGURED
+
+# Set your own Zulip instance (local testing only)
+# ZULIP_URL=https://testinstance.zulichat.com
+
+# Used for authenticating a bot
+# ZULIP_BOT_EMAIL=bot@testinstance.zulipchat.com
+# ZULIP_API_TOKEN=yyy
+
+# Authenticates inbound webhooks from Github
+# ZULIP_TOKEN=xxx
\ No newline at end of file
diff --git a/README.md b/README.md
index 436926bf..814b036f 100644
--- a/README.md
+++ b/README.md
@@ -95,6 +95,10 @@ gh webhook forward --repo=ehuss/triagebot-test --events=* \
Where the value in `--secret` is the secret value you place in `GITHUB_WEBHOOK_SECRET` in the `.env` file, and `--repo` is the repo you want to test against.
+### Zulip testing
+
+If you are modifying code that sends message to Zulip and want to test your changes, you can register a [new free Zulip instance](https://zulip.com/new/). Before launching the triagebot locally, set the Zulip env vars to connect to your test instance (see example in `.env.sample`).
+
#### ngrok
The following is an example of using to provide webhook forwarding.
diff --git a/src/zulip.rs b/src/zulip.rs
index 8e77ab82..615670f8 100644
--- a/src/zulip.rs
+++ b/src/zulip.rs
@@ -9,8 +9,12 @@ use anyhow::{format_err, Context as _};
use std::env;
use std::fmt::Write as _;
use std::str::FromStr;
+use std::sync::LazyLock;
use tracing as log;
+static ZULIP_URL: LazyLock =
+ LazyLock::new(|| env::var("ZULIP_URL").unwrap_or("https://rust-lang.zulipchat.com".into()));
+
#[derive(Debug, serde::Deserialize)]
pub struct Request {
/// Markdown body of the sent message.
@@ -71,8 +75,6 @@ struct Response {
content: String,
}
-pub const BOT_EMAIL: &str = "triage-rust-lang-bot@zulipchat.com";
-
pub async fn to_github_id(client: &GithubClient, zulip_id: u64) -> anyhow::Result