diff --git a/obelisk/frontend/src/Frontend.hs b/obelisk/frontend/src/Frontend.hs
index 36eec545d2f78862bf152454d99eaa6032083560..d220d33a4169239573f1988f45b11902f443a826 100644
--- a/obelisk/frontend/src/Frontend.hs
+++ b/obelisk/frontend/src/Frontend.hs
@@ -33,7 +33,10 @@ frontend = Frontend
       elAttr "link" ("href" =: mainCss <> "type" =: "text/css" <> "rel" =: "stylesheet") blank
 
   -- Obelisk.Route.Frontend.RoutedT t (R FrontendRoute) m ()
-  , _frontend_body = subRoute_ pageFromRoute
+  , _frontend_body = do
+      -- TODO This might be a good place to create the MagicFolder "client"
+      magicFolders <- (listMagicFolders ...)
+      subRoute_ pageFromRoute magicFolders
   }
 
 -- mapRoutedT :: (m a -> n b) -> RoutedT t r m a -> RoutedT t r n b
diff --git a/obelisk/frontend/src/MagicFolder.hs b/obelisk/frontend/src/MagicFolder.hs
index ea43512cc3bd0453aed49e0c9879a2ca2d0246aa..967d6b3c267008ef8d9918c46f48f91e1a10633f 100644
--- a/obelisk/frontend/src/MagicFolder.hs
+++ b/obelisk/frontend/src/MagicFolder.hs
@@ -1,7 +1,13 @@
+{-# LANGUAGE FlexibleContexts #-}
+
 module MagicFolder where
 
 import Data.Text
 
+import Control.Monad.IO.Class
+import Reflex.Dom.Core
+import qualified Tahoe.CHK.Capability as Cap
+
 newtype MagicFolder = MagicFolder Text deriving (Eq, Ord, Show)
 data FolderEntry
     = File
@@ -14,3 +20,38 @@ data FolderEntry
       , directoryChildCount :: Int
       }
     deriving (Eq, Ord, Show)
+
+data Announcements = Announcements
+data LookupServer = LookupServer
+data ListError = Initializing | NetworkError
+
+listMagicFolders ::
+  (MonadIO (Performable m), Reflex t, PostBuild t m, MonadHold t m, PerformEvent t m) =>
+  LookupServer ->
+  -- XX These might be fire-once.  You don't want to miss the firing.  Maybe
+  -- we should take Dynamics instead.
+  Dynamic t Announcements ->
+  Dynamic t (Maybe Cap.Reader) ->
+  m (Dynamic t (Either ListError [MagicFolder]))
+listMagicFolders lookupServer announcementsDyn capDyn = do
+  -- annBhr <- hold mempty announcementsEv
+  -- capBhr <- hold Nothing capEv
+
+  pb <- getPostBuild
+  -- maybe also a tickLossyFromPostBuildTime too
+  let refreshEv =
+        mergeWith (<>) [pb, () <$ updated announcementsDyn, () <$ updated capDyn]
+
+      downloadParamEv = tagPromptlyDyn ((,) <$> announcementsDyn <*> capDyn) refreshEv
+
+      downloadParamEv' = fmapMaybe (\(ann, cap) -> (fmap ((,) ann) cap)) downloadParamEv
+
+  magicFoldersEv <- performEvent $ ffor downloadParamEv' $ \(ann, cap) ->
+    liftIO $ downloadMagicFolders lookupServer ann cap
+
+  -- the network operation will take some time
+  -- is this a reasonable way to handle the "we're not sure yet" state?
+  holdDyn (Left Initializing) magicFoldersEv
+
+downloadMagicFolders :: LookupServer -> Announcements -> Cap.Reader -> IO (Either ListError [MagicFolder])
+downloadMagicFolders = undefined