diff --git a/async/src/simple_client.rs b/async/src/simple_client.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0c6b0a762f846ccffbfe883ec04004ef458e6ce6
--- /dev/null
+++ b/async/src/simple_client.rs
@@ -0,0 +1,150 @@
+#[allow(unused_imports)]
+use log::{debug, error, info, log, trace, warn};
+
+use core::str::FromStr;
+
+use door::SignKey;
+use door_sshproto as door;
+use door_sshproto::{BhError, BhResult};
+use door_sshproto::{ChanMsg, ChanMsgDetails, Error, RespPackets, Result, Runner};
+
+use std::collections::VecDeque;
+
+use async_trait::async_trait;
+
+pub struct SimpleClient {
+    auth_done: bool,
+    main_ch: Option<u32>,
+    authkeys: VecDeque<SignKey>,
+    username: String,
+}
+
+impl SimpleClient {
+    pub fn new(username: &impl AsRef<str>) -> Self {
+        SimpleClient {
+            auth_done: false,
+            main_ch: None,
+            authkeys: VecDeque::new(),
+            username: username.as_ref().into(),
+        }
+    }
+
+    pub fn add_authkey(&mut self, k: SignKey) {
+        self.authkeys.push_back(k)
+    }
+}
+
+// #[async_trait(?Send)]
+#[async_trait]
+impl door::AsyncCliBehaviour for SimpleClient {
+    async fn chan_handler(
+        &mut self,
+        _resp: &mut RespPackets,
+        chan_msg: ChanMsg,
+    ) -> Result<()> {
+        if Some(chan_msg.num) != self.main_ch {
+            return Err(Error::SSHProtoError);
+        }
+
+        match chan_msg.msg {
+            ChanMsgDetails::ExtData { .. } => {}
+            ChanMsgDetails::Req { .. } => {}
+            _ => {}
+        }
+        Ok(())
+    }
+
+    async fn username(&mut self) -> BhResult<door::ResponseString> {
+        door::ResponseString::from_str(&self.username).map_err(|_| BhError::Fail)
+    }
+
+    async fn valid_hostkey(&mut self, key: &door::PubKey) -> BhResult<bool> {
+        trace!("valid_hostkey for {key:?}");
+        Ok(true)
+    }
+
+    async fn next_authkey(&mut self) -> BhResult<Option<door::SignKey>> {
+        Ok(self.authkeys.pop_front())
+    }
+
+    async fn auth_password(
+        &mut self,
+        pwbuf: &mut door::ResponseString,
+    ) -> BhResult<bool> {
+        let pw =
+            rpassword::prompt_password(format!("password for {}: ", self.username))
+                .map_err(|e| {
+                    warn!("read_password failed {e:}");
+                    BhError::Fail
+                })?;
+        if pwbuf.push_str(&pw).is_err() {
+            Err(BhError::Fail)
+        } else {
+            Ok(true)
+        }
+    }
+
+    async fn authenticated(&mut self) {
+        info!("Authentication succeeded");
+        self.auth_done = true;
+    }
+    // }
+
+    // impl door::BlockCliBehaviour for SimpleClient {
+    //     fn chan_handler<'f>(&mut self, resp: &mut RespPackets, chan_msg: ChanMsg<'f>) -> Result<()> {
+    //         if Some(chan_msg.num) != self.main_ch {
+    //             return Err(Error::SSHProtoError)
+    //         }
+
+    //         match chan_msg.msg {
+    //             ChanMsgDetails::Data(buf) => {
+    //                 let _ = std::io::stdout().write_all(buf);
+    //             },
+    //             ChanMsgDetails::ExtData{..} => {
+    //             }
+    //             ChanMsgDetails::Req{..} => {
+    //             }
+    //             _ => {}
+    //         }
+    //         Ok(())
+    //     }
+
+    //     fn progress(&mut self, runner: &mut Runner) -> Result<()> {
+    //         if self.auth_done {
+    //             if self.main_ch.is_none() {
+    //                 let ch = runner.open_client_session(Some("cowsay it works"), false)?;
+    //                 self.main_ch = Some(ch);
+    //             }
+    //         }
+    //         Ok(())
+    //     }
+
+    //     fn username(&mut self) -> BhResult<door::ResponseString> {
+    //         // TODO unwrap
+    //         let mut p = door::ResponseString::new();
+    //         p.push_str("matt").unwrap();
+    //         Ok(p)
+    //     }
+
+    //     fn valid_hostkey(&mut self, key: &door::PubKey) -> BhResult<bool> {
+    //         trace!("valid_hostkey for {key:?}");
+    //         Ok(true)
+    //     }
+
+    //     fn auth_password(&mut self, pwbuf: &mut door::ResponseString) -> BhResult<bool> {
+    //         let pw = rpassword::prompt_password("password: ").map_err(|e| {
+    //             warn!("read_password failed {e:}");
+    //             BhError::Fail
+    //         })?;
+    //         if pwbuf.push_str(&pw).is_err() {
+    //             Err(BhError::Fail)
+    //         } else {
+    //             Ok(true)
+    //         }
+    //     }
+
+    //     fn authenticated(&mut self) {
+    //         info!("Authentication succeeded");
+    //         self.auth_done = true;
+    //     }
+}