diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # Revision history for glirc2
 
+## 2.21.1
+
+* Support for latest config-schema
+* Adapt extension API to help support stub Rust extension
+
 ## 2.21
 
 * Make metadata toggle (F4) a window-level setting instead of client level
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
 GLIRC - Advanced Console IRC Client
 =============
 
-[![Build Status](https://secure.travis-ci.org/glguy/irc-core.svg)](http://travis-ci.org/glguy/irc-core)
+* **glirc** [![Hackage](https://img.shields.io/hackage/v/glirc.svg)](https://hackage.haskell.org/package/glirc) [![Build Status](https://secure.travis-ci.org/glguy/irc-core.svg)](http://travis-ci.org/glguy/irc-core)
+* **irc-core** [![Hackage](https://img.shields.io/hackage/v/irc-core.svg)](https://hackage.haskell.org/package/irc-core)
+* **hookup** [![Hackage](https://img.shields.io/hackage/v/hookup.svg)](https://hackage.haskell.org/package/hookup)
 
 [Wiki Documentation](https://github.com/glguy/irc-core/wiki)
 
@@ -10,8 +12,6 @@
 Building
 ========
 
-Note that glirc currently requires GHC 8.0.1
-
 glirc uses recent versions of packages, make sure you package databases are
 up-to-date:
 
@@ -39,6 +39,9 @@
 $ stack init --resolver=lts-8 --solver
 $ stack build
 ```
+
+Note that if you're using a *nightly* resolver that you'll need to work around a
+bug in stack by manually installing `alex` and `happy`.
 
 Client Features
 ===============
diff --git a/exec/linux_exported_symbols.txt b/exec/linux_exported_symbols.txt
--- a/exec/linux_exported_symbols.txt
+++ b/exec/linux_exported_symbols.txt
@@ -8,4 +8,6 @@
 glirc_my_nick;
 glirc_mark_seen;
 glirc_clear_window;
+glirc_free_string;
+glirc_free_strings;
 };
diff --git a/exec/macos_exported_symbols.txt b/exec/macos_exported_symbols.txt
--- a/exec/macos_exported_symbols.txt
+++ b/exec/macos_exported_symbols.txt
@@ -7,3 +7,5 @@
 _glirc_my_nick
 _glirc_mark_seen
 _glirc_clear_window
+_glirc_free_string
+_glirc_free_strings
diff --git a/glirc.cabal b/glirc.cabal
--- a/glirc.cabal
+++ b/glirc.cabal
@@ -1,5 +1,5 @@
 name:                glirc
-version:             2.21
+version:             2.21.1
 synopsis:            Console IRC client
 description:         Console IRC client
                      .
@@ -11,7 +11,7 @@
 license-file:        LICENSE
 author:              Eric Mertens
 maintainer:          emertens@gmail.com
-copyright:           2016 Eric Mertens
+copyright:           2016,2017 Eric Mertens
 category:            Network
 build-type:          Custom
 extra-source-files:  ChangeLog.md README.md
@@ -129,7 +129,7 @@
                        bytestring           >=0.10.8 && <0.11,
                        base64-bytestring    >=1.0.0.1 && <1.1,
                        config-value         >=0.6    && <0.7,
-                       config-schema        >=0.3    && <0.4,
+                       config-schema        >=0.4    && <0.5,
                        containers           >=0.5.7  && <0.6,
                        directory            >=1.2.6  && <1.4,
                        filepath             >=1.4.1  && <1.5,
diff --git a/include/glirc-api.h b/include/glirc-api.h
--- a/include/glirc-api.h
+++ b/include/glirc-api.h
@@ -3,6 +3,8 @@
 
 #include <stdlib.h>
 
+struct glirc;
+
 enum message_code {
         NORMAL_MESSAGE = 0,
         ERROR_MESSAGE  = 1
@@ -24,25 +26,25 @@
         struct glirc_string prefix_user;
         struct glirc_string prefix_host;
         struct glirc_string command;
-        struct glirc_string *params;
+        const struct glirc_string *params;
         size_t params_n;
-        struct glirc_string *tagkeys;
-        struct glirc_string *tagvals;
+        const struct glirc_string *tagkeys;
+        const struct glirc_string *tagvals;
         size_t tags_n;
 };
 
 struct glirc_command {
-        struct glirc_string *params;
+        const struct glirc_string *params;
         size_t params_n;
 };
 
-typedef void *start_type         (void *glirc, const char *path);
-typedef void stop_type           (void *glirc, void *S);
-typedef enum process_result process_message_type(void *glirc, void *S, const struct glirc_message *);
-typedef void process_command_type(void *glirc, void *S, const struct glirc_command *);
+typedef void *start_type         (struct glirc *G, const char *path);
+typedef void stop_type           (struct glirc *G, void *S);
+typedef enum process_result process_message_type(struct glirc *G, void *S, const struct glirc_message *);
+typedef void process_command_type(struct glirc *G, void *S, const struct glirc_command *);
 
 struct glirc_extension {
-        char *name;
+        const char *name;
         int major_version, minor_version;
         start_type           *start;
         stop_type            *stop;
@@ -50,14 +52,17 @@
         process_command_type *process_command;
 };
 
-int glirc_send_message(void *glirc, const struct glirc_message *);
-int glirc_print(void *glirc, enum message_code, struct glirc_string msg);
-char ** glirc_list_networks(void *glirc);
-char ** glirc_list_channels(void *glirc, struct glirc_string network);
-char ** glirc_list_channel_users(void *glirc, struct glirc_string network, struct glirc_string channel);
-char * glirc_my_nick(void *glirc, struct glirc_string network);
-void glirc_mark_seen(void *glirc, struct glirc_string network, struct glirc_string channel);
-void glirc_clear_window(void *glirc, struct glirc_string network, struct glirc_string channel);
+int glirc_send_message(struct glirc *G, const struct glirc_message *);
+int glirc_print(struct glirc *G, enum message_code, struct glirc_string msg);
+char ** glirc_list_networks(struct glirc *G);
+char ** glirc_list_channels(struct glirc *G, struct glirc_string network);
+char ** glirc_list_channel_users(struct glirc *G, struct glirc_string network, struct glirc_string channel);
+char * glirc_my_nick(struct glirc *G, struct glirc_string network);
+void glirc_mark_seen(struct glirc *G, struct glirc_string network, struct glirc_string channel);
+void glirc_clear_window(struct glirc *G, struct glirc_string network, struct glirc_string channel);
 int glirc_identifier_cmp(struct glirc_string s, struct glirc_string t);
+
+void glirc_free_string(char *);
+void glirc_free_strings(char **);
 
 #endif
diff --git a/src/Client/CApi/Exports.hs b/src/Client/CApi/Exports.hs
--- a/src/Client/CApi/Exports.hs
+++ b/src/Client/CApi/Exports.hs
@@ -20,6 +20,8 @@
  , Glirc_identifier_cmp
  , Glirc_mark_seen
  , Glirc_clear_window
+ , Glirc_free_string
+ , Glirc_free_strings
  ) where
 
 import           Client.CApi.Types
@@ -32,6 +34,8 @@
 import           Control.Concurrent.MVar
 import           Control.Exception
 import           Control.Lens
+import           Control.Monad (unless)
+import           Data.Foldable (traverse_)
 import qualified Data.HashMap.Strict as HashMap
 import           Data.Text (Text)
 import qualified Data.Text as Text
@@ -331,3 +335,36 @@
      mvar <- derefToken stab
      modifyMVar_ mvar $ \st ->
        return $! set (clientWindows . ix focus) emptyWindow st
+
+------------------------------------------------------------------------
+
+-- | Free one of the heap allocated strings found as a return value
+-- from the extension API. If argument is NULL, nothing happens.
+type Glirc_free_string =
+  CString {- ^ glirc allocated string -} ->
+  IO ()
+
+#ifdef EXPORT_GLIRC_CAPI
+foreign export ccall glirc_free_string :: Glirc_free_string
+#endif
+
+glirc_free_string :: Glirc_free_string
+glirc_free_string = free
+
+------------------------------------------------------------------------
+
+-- | Free an array of heap allocated strings found as a return value
+-- from the extension API. If argument is NULL, nothing happens.
+type Glirc_free_strings =
+  Ptr CString {- ^ glirc allocated strings, null-terminated -} ->
+  IO ()
+
+#ifdef EXPORT_GLIRC_CAPI
+foreign export ccall glirc_free_strings :: Glirc_free_strings
+#endif
+
+glirc_free_strings :: Glirc_free_strings
+glirc_free_strings p =
+  unless (p == nullPtr) $
+    do traverse_ free =<< peekArray0 nullPtr p
+       free p
diff --git a/src/Client/Commands.hs b/src/Client/Commands.hs
--- a/src/Client/Commands.hs
+++ b/src/Client/Commands.hs
@@ -1627,7 +1627,6 @@
     -- be considered a hint for tab completion.
     summaryActor :: IrcSummary -> Maybe Identifier
     summaryActor (ChatSummary who) = Just who
-    summaryActor (JoinSummary who) = Just who
     summaryActor _                 = Nothing
 
 -- | Use the *!*@host masks of users for channel lists when setting list modes
diff --git a/src/Client/Configuration.hs b/src/Client/Configuration.hs
--- a/src/Client/Configuration.hs
+++ b/src/Client/Configuration.hs
@@ -211,7 +211,7 @@
        Right cfg -> return (cfg mbPath def)
 
 
-explainLoadError :: LoadError -> Text
+explainLoadError :: LoadError Position -> Text
 explainLoadError (LoadError pos path problem) =
   Text.concat [ positionText, " at ", pathText, ": ", problemText]
 
