diff --git a/gnu/local.mk b/gnu/local.mk
index 0f62c8e1d7..1ed6dfc7ca 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -456,6 +456,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/slang.scm			\
   %D%/packages/smalltalk.scm			\
   %D%/packages/sml.scm				\
+  %D%/packages/spacemacs.scm			\
   %D%/packages/speech.scm			\
   %D%/packages/sphinx.scm			\
   %D%/packages/spice.scm			\
@@ -1345,6 +1346,9 @@ dist_patch_DATA =						\
   %D%/packages/patches/scalapack-blacs-mpi-deprecations.patch	\
   %D%/packages/patches/scheme48-tests.patch			\
   %D%/packages/patches/scotch-build-parallelism.patch		\
+  %D%/packages/patches/spacemacs-rolling-release-add-data-dir.patch	\
+  %D%/packages/patches/spacemacs-rolling-release-inhibit-read-only.patch	\
+  %D%/packages/patches/spacemacs-rolling-release-quelpa-permissions.patch	\
   %D%/packages/patches/scotch-integer-declarations.patch	\
   %D%/packages/patches/sdl-libx11-1.6.patch			\
   %D%/packages/patches/sdl2-mesa-compat.patch			\
diff --git a/gnu/packages/patches/spacemacs-rolling-release-add-data-dir.patch b/gnu/packages/patches/spacemacs-rolling-release-add-data-dir.patch
new file mode 100644
index 0000000000..cb92d0b036
--- /dev/null
+++ b/gnu/packages/patches/spacemacs-rolling-release-add-data-dir.patch
@@ -0,0 +1,259 @@
+Spacemacs uses ~/.emacs.d in 2 ways: to store the code implementing the
+spacemacs framework and to track state. When we tell spacemacs that it lives
+in the store it tries to use the store location to track state as well. This
+patch adds a new variable, spacemacs-data-directory, for keeping track of state.
+This defaults to spacemacs-start-directory for upstream compatibility.
+
+diff --git a/core/core-configuration-layer.el b/core/core-configuration-layer.el
+index 740b700cf..c8253dc9b 100644
+--- a/core/core-configuration-layer.el
++++ b/core/core-configuration-layer.el
+@@ -120,7 +120,7 @@ subdirectory of ROOT is used."
+   "Hook executed at the end of configuration loading.")
+
+ (defconst configuration-layer--elpa-root-directory
+-  (concat spacemacs-start-directory "elpa/")
++  (concat spacemacs-data-directory "elpa/")
+   "Spacemacs ELPA root directory.")
+
+ (defconst configuration-layer--rollback-root-directory
+diff --git a/core/core-documentation.el b/core/core-documentation.el
+index 96bfc4a87..3a3ef456d 100644
+--- a/core/core-documentation.el
++++ b/core/core-documentation.el
+@@ -289,7 +289,7 @@ preprocessors for the exported .org files."
+               });
+           });
+           </script>")
+-         (publish-target (concat spacemacs-start-directory "export/"))
++         (publish-target (concat spacemacs-data-directory "export/"))
+          (org-html-htmlize-output-type 'css)
+          (org-publish-project-alist
+           `(("spacemacs"
+diff --git a/core/core-funcs.el b/core/core-funcs.el
+index 28e7290a5..2f09c1df7 100644
+--- a/core/core-funcs.el
++++ b/core/core-funcs.el
+@@ -274,7 +274,7 @@ result, incrementing passed-tests and total-tests."
+      (lambda (fname)
+        (when (file-exists-p fname)
+          (delete-file fname)))
+-     (directory-files-recursively user-emacs-directory "\\.elc$" t)))
++     (directory-files-recursively spacemacs-data-directory "\\.elc$" t)))
+   (byte-recompile-directory package-user-dir 0 arg))
+
+ (defun spacemacs/register-repl (feature repl-func &optional tag)
+diff --git a/core/core-load-paths.el b/core/core-load-paths.el
+index 718b27ce4..90c0c28ad 100644
+--- a/core/core-load-paths.el
++++ b/core/core-load-paths.el
+@@ -19,6 +19,11 @@
+ (defvar spacemacs-start-directory
+   user-emacs-directory
+   "Spacemacs start directory.")
++(defvar spacemacs-data-directory
++  user-emacs-directory
++  "Writable directory for spacemacs data")
++(unless (file-exists-p spacemacs-data-directory)
++  (make-directory spacemacs-data-directory))
+ (defconst spacemacs-core-directory
+   (expand-file-name (concat spacemacs-start-directory "core/"))
+   "Spacemacs core directory.")
+@@ -45,7 +50,7 @@
+   (expand-file-name (concat spacemacs-banner-directory "img/heart.png"))
+   "Purple heart emoji.")
+ (defconst spacemacs-cache-directory
+-  (expand-file-name (concat user-emacs-directory ".cache/"))
++  (expand-file-name (concat spacemacs-data-directory ".cache/"))
+   "Spacemacs storage area for persistent files")
+ (defconst spacemacs-auto-save-directory
+   (expand-file-name (concat spacemacs-cache-directory "auto-save/"))
+diff --git a/core/core-release-management.el b/core/core-release-management.el
+index 989ccb124..db0f5c76d 100644
+--- a/core/core-release-management.el
++++ b/core/core-release-management.el
+@@ -99,6 +99,10 @@ found."
+          (not (spacemacs//can-check-for-new-version-at-startup)))
+     (message (concat "Skipping check for new version "
+                      "(reason: last check is too recent)")))
++   ((and (not force)
++         (or (string-prefix-p "/gnu/store" spacemacs-start-directory)
++             (string-prefix-p "/nix/store" spacemacs-start-directory)))
++    (message (concat "Skipping check for new version (reason: on guix or nix)")))
+    ((require 'async nil t)
+     (message "Start checking for new version...")
+     (async-start
+diff --git a/core/libs/quelpa.el b/core/libs/quelpa.el
+index 70b143657..9da420028 100644
+--- a/core/libs/quelpa.el
++++ b/core/libs/quelpa.el
+@@ -79,7 +79,7 @@ the `:upgrade' argument."
+   :group 'quelpa
+   :type 'hook)
+
+-(defcustom quelpa-dir (expand-file-name "quelpa" user-emacs-directory)
++(defcustom quelpa-dir (expand-file-name "quelpa" spacemacs-data-directory)
+   "Where quelpa builds and stores packages."
+   :group 'quelpa
+   :type 'string)
+diff --git a/tests/core/core-configuration-layer-utest.el b/tests/core/core-configuration-layer-utest.el
+index 0d300142b..e5877932c 100644
+--- a/tests/core/core-configuration-layer-utest.el
++++ b/tests/core/core-configuration-layer-utest.el
+@@ -880,16 +880,16 @@
+ (ert-deftest test-make-layer--make-layer-from-symbol-with-a-dir ()
+   (should (equal (cfgl-layer "layer"
+                              :name 'layer
+-                             :dir spacemacs-start-directory)
++                             :dir spacemacs-data-directory)
+                  (configuration-layer/make-layer
+-                  'layer nil nil spacemacs-start-directory))))
++                  'layer nil nil spacemacs-data-directory))))
+
+ (ert-deftest test-make-layer--make-layer-from-spec-with-a-dir ()
+   (should (equal (cfgl-layer "layer"
+                              :name 'layer
+-                             :dir spacemacs-start-directory)
++                             :dir spacemacs-data-directory)
+                  (configuration-layer/make-layer
+-                  '(layer :name 'layer) nil nil spacemacs-start-directory))))
++                  '(layer :name 'layer) nil nil spacemacs-data-directory))))
+
+ (ert-deftest test-make-layer--cannot-make-layer-without-a-directory ()
+   (mocker-let
+@@ -908,10 +908,10 @@
+ (ert-deftest test-make-layer--make-layer-without-a-dir-requires-an-initial-obj ()
+   (let ((layer (cfgl-layer "layer"
+                            :name 'layer
+-                           :dir spacemacs-start-directory)))
++                           :dir spacemacs-data-directory)))
+     (should (equal (cfgl-layer "layer"
+                                :name 'layer
+-                               :dir spacemacs-start-directory)
++                               :dir spacemacs-data-directory)
+                    (configuration-layer/make-layer 'layer layer)))))
+
+ ;; load packages
+@@ -919,7 +919,7 @@
+ (ert-deftest test-make-layer--make-used-layer-loads-packages-file ()
+   (let ((layer (cfgl-layer "layer"
+                            :name 'layer
+-                           :dir spacemacs-start-directory))
++                           :dir spacemacs-data-directory))
+         (layer-packages '(pkg1 pkg2 pkg3))
+         (mocker-mock-default-record-cls 'mocker-stub-record))
+     (mocker-let
+@@ -931,13 +931,13 @@
+                                 :variables nil
+                                 :packages '(pkg1 pkg2 pkg3)
+                                 :selected-packages 'all
+-                                :dir spacemacs-start-directory)
++                                :dir spacemacs-data-directory)
+               (configuration-layer/make-layer 'layer layer 'used))))))
+
+ (ert-deftest test-make-layer--make-layer-force-load-packages-file-with-var ()
+   (let ((layer (cfgl-layer "layer"
+                            :name 'layer
+-                           :dir spacemacs-start-directory))
++                           :dir spacemacs-data-directory))
+         (layer-packages '(pkg1 pkg2 pkg3))
+         (configuration-layer--load-packages-files t)
+         (mocker-mock-default-record-cls 'mocker-stub-record))
+@@ -950,13 +950,13 @@
+                                 :variables nil
+                                 :packages '(pkg1 pkg2 pkg3)
+                                 :selected-packages 'all
+-                                :dir spacemacs-start-directory)
++                                :dir spacemacs-data-directory)
+                     (configuration-layer/make-layer 'layer layer))))))
+
+ (ert-deftest test-make-layer--make-layer-does-not-load-packages-file-by-default ()
+   (let ((layer (cfgl-layer "layer"
+                            :name 'layer
+-                           :dir spacemacs-start-directory))
++                           :dir spacemacs-data-directory))
+         (layer-packages '(pkg1))
+         (mocker-mock-default-record-cls 'mocker-stub-record))
+     (mocker-let
+@@ -968,7 +968,7 @@
+ (ert-deftest test-make-layer--make-used-layer-can-set-additional-properties ()
+   (let ((layer (cfgl-layer "layer"
+                            :name 'layer
+-                           :dir spacemacs-start-directory))
++                           :dir spacemacs-data-directory))
+         (layer-specs '(layer :disabled-for pkg8 pkg9
+                              :can-shadow layer2 layer3
+                              :variables foo bar toto 1))
+@@ -984,13 +984,13 @@
+                                 :variables '(foo bar toto 1)
+                                 :packages '(pkg1 pkg2 pkg3)
+                                 :selected-packages 'all
+-                                :dir spacemacs-start-directory)
++                                :dir spacemacs-data-directory)
+                     (configuration-layer/make-layer layer-specs layer 'used))))))
+
+ (ert-deftest test-make-layer--make-not-used-layer-cannot-set-additional-properties ()
+   (let ((layer (cfgl-layer "layer"
+                            :name 'layer
+-                           :dir spacemacs-start-directory))
++                           :dir spacemacs-data-directory))
+         (layer-specs '(layer :disabled-for pkg8 pkg9
+                              :can-shadow layer2
+                              :variables foo bar toto 1))
+@@ -1002,7 +1002,7 @@
+                                :variables nil
+                                :packages nil
+                                :selected-packages 'all
+-                               :dir spacemacs-start-directory)
++                               :dir spacemacs-data-directory)
+                    (configuration-layer/make-layer layer-specs layer)))))
+
+ (ert-deftest test-make-layer--make-used-layer-can-override-additional-properties ()
+@@ -1011,7 +1011,7 @@
+                            :disabled-for '(pkg10)
+                            :can-shadow '()
+                            :variables '(titi tata tutu 1)
+-                           :dir spacemacs-start-directory))
++                           :dir spacemacs-data-directory))
+         (layer-specs '(layer :disabled-for pkg8 pkg9
+                              :can-shadow layer2
+                              :variables foo bar toto 1))
+@@ -1027,7 +1027,7 @@
+                                 :variables '(foo bar toto 1)
+                                 :packages '(pkg1 pkg2 pkg3)
+                                 :selected-packages 'all
+-                                :dir spacemacs-start-directory)
++                                :dir spacemacs-data-directory)
+                     (configuration-layer/make-layer layer-specs layer 'used))))))
+
+ (ert-deftest test-make-layer--make-not-used-layer-cannot-override-additional-properties ()
+@@ -1038,7 +1038,7 @@
+                            :variables '(titi tata tutu 1)
+                            :packages '(pkg1 pkg2 pkg3)
+                            :selected-packages 'all
+-                           :dir spacemacs-start-directory))
++                           :dir spacemacs-data-directory))
+         (layer-specs '(layer :disabled-for pkg8 pkg9
+                              :can-shadow '(layer2)
+                              :variables foo bar toto 1))
+@@ -1050,7 +1050,7 @@
+                                :variables '(titi tata tutu 1)
+                                :packages '(pkg1 pkg2 pkg3)
+                                :selected-packages 'all
+-                               :dir spacemacs-start-directory)
++                               :dir spacemacs-data-directory)
+                    (configuration-layer/make-layer layer-specs layer)))))
+
+ ;; ---------------------------------------------------------------------------
+diff --git a/tests/doc/org-export-ftest.el b/tests/doc/org-export-ftest.el
+index 4ee86c897..cdd731eec 100644
+--- a/tests/doc/org-export-ftest.el
++++ b/tests/doc/org-export-ftest.el
+@@ -59,6 +59,6 @@
+ ;; -----------------------------------------------------------------------------
+ (ert-deftest test-spacemacs-html-export ()
+   (unwind-protect (spacemacs/publish-doc)
+-    (delete-directory (concat spacemacs-start-directory
++    (delete-directory (concat spacemacs-data-directory
+                               "export/")
+                       t)))
diff --git a/gnu/packages/patches/spacemacs-rolling-release-inhibit-read-only.patch b/gnu/packages/patches/spacemacs-rolling-release-inhibit-read-only.patch
new file mode 100644
index 0000000000..4cb184a898
--- /dev/null
+++ b/gnu/packages/patches/spacemacs-rolling-release-inhibit-read-only.patch
@@ -0,0 +1,44 @@
+The first time that a user runs spacemacs it will open the default
+configuration from the source tree and modify the buffer. The buffer is
+read-only since the file it opened is, but since we save the file to the users
+home directory and not back to it's original location temporarily inhibiting
+read-only solves our problem.
+
+diff --git a/core/core-dotspacemacs.el b/core/core-dotspacemacs.el
+index f28249148..3b7872ff0 100644
+--- a/core/core-dotspacemacs.el
++++ b/core/core-dotspacemacs.el
+@@ -643,19 +643,20 @@ If ARG is non nil then Ask questions to the user before installing the dotfile."
+     (with-current-buffer (find-file-noselect
+                           (concat dotspacemacs-template-directory
+                                   ".spacemacs.template"))
+-      (dolist (p preferences)
+-        (goto-char (point-min))
+-        (re-search-forward (car p))
+-        (replace-match (cadr p)))
+-      (let ((install
+-             (if (file-exists-p dotspacemacs-filepath)
+-                 (y-or-n-p
+-                  (format "%s already exists. Do you want to overwrite it ? "
+-                          dotspacemacs-filepath)) t)))
+-        (when install
+-          (write-file dotspacemacs-filepath)
+-          (message "%s has been installed." dotspacemacs-filepath)
+-          t))))
++      (let ((inhibit-read-only t))
++        (dolist (p preferences)
++          (goto-char (point-min))
++          (re-search-forward (car p))
++          (replace-match (cadr p)))
++        (let ((install
++               (if (file-exists-p dotspacemacs-filepath)
++                   (y-or-n-p
++                    (format "%s already exists. Do you want to overwrite it ? "
++                            dotspacemacs-filepath)) t)))
++          (when install
++            (write-file dotspacemacs-filepath)
++            (message "%s has been installed." dotspacemacs-filepath)
++            t)))))
+   (dotspacemacs/load-file)
+   ;; force new wizard values to be applied
+   (dotspacemacs/init))
diff --git a/gnu/packages/patches/spacemacs-rolling-release-quelpa-permissions.patch b/gnu/packages/patches/spacemacs-rolling-release-quelpa-permissions.patch
new file mode 100644
index 0000000000..96016d6935
--- /dev/null
+++ b/gnu/packages/patches/spacemacs-rolling-release-quelpa-permissions.patch
@@ -0,0 +1,53 @@
+When quelpa builds some packages it has to copy files from the store, which
+means that they are marked as read-only. This patch sets the permissions of
+copied files and directories to ensure that they are writable.
+
+diff --git a/core/libs/quelpa.el b/core/libs/quelpa.el
+index 70b143657..9da420028 100644
+@@ -374,8 +374,10 @@ and return TIME-STAMP, otherwise return OLD-TIME-STAMP."
+         (delete-directory dir t)
+         (make-directory dir)
+         (if (eq type 'file)
+-            (copy-file file-path dir t t t t)
+-          (copy-directory file-path dir t t t)))
++          (progn (copy-file file-path dir t t t t)
++                 (set-file-modes (expand-file-name (file-name-nondirectory file-path) dir) #o644))
++          (progn (copy-directory file-path dir t t t)
++                 (set-file-modes dir #o755))))
+       (quelpa-build--dump new-stamp-info stamp-file)
+       (quelpa-file-version file-path type version time-stamp))))
+
+@@ -1369,10 +1371,13 @@ FILES is a list of (SOURCE . DEST) relative filepath pairs."
+   (cond
+    ((file-regular-p file)
+     (quelpa-build--message "%s -> %s" file newname)
+-    (copy-file file newname))
++    (copy-file file newname)
++    (set-file-modes newname #o644))
+    ((file-directory-p file)
+     (quelpa-build--message "%s => %s" file newname)
+-    (copy-directory file newname))))
++    (make-directory newname)
++    (set-file-modes newname #o755)
++    (map quelpa-build--copy-file (directory-files file t)))))
+
+ (defun quelpa-build--find-source-file (target files)
+   "Search for source of TARGET in FILES."
+@@ -1463,6 +1468,7 @@ Returns the archive entry for the package."
+     (if (file-exists-p pkg-target)
+         (quelpa-build--message "Skipping rebuild of %s" pkg-target)
+       (copy-file pkg-source pkg-target)
++      (set-file-modes pkg-target #o644)
+       (let ((enable-local-variables nil)
+             (make-backup-files nil))
+         (with-temp-buffer
+@@ -1566,7 +1572,8 @@ attribute with an URL like \"http://domain.tld/path/to/file.el\"."
+     (unless (string= (file-name-extension url) "el")
+       (error "<%s> does not end in .el" url))
+     (unless (file-directory-p dir)
+-      (make-directory dir))
++      (make-directory dir)
++      (set-file-modes dir #o755))
+     (url-copy-file url local-path t)
+     (quelpa-check-hash name config local-path dir 'url)))
+
diff --git a/gnu/packages/spacemacs.scm b/gnu/packages/spacemacs.scm
new file mode 100644
index 0000000000..24b3f23428
--- /dev/null
+++ b/gnu/packages/spacemacs.scm
@@ -0,0 +1,119 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Bryan Ferris <saffronsnail@protonmail.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu packages spacemacs)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages base)
+  #:use-module (gnu packages bash)
+  #:use-module (gnu packages compression)
+  #:use-module (gnu packages emacs)
+
+  #:use-module (guix build-system trivial)
+  #:use-module (guix download)
+  #:use-module (guix gexp)
+  #:use-module (guix git-download)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (guix utils))
+
+(define-public spacemacs-rolling-release
+  (let ((commit "1e278a3cb9cd4730ee17416b55fb778b62da2fd0"))
+    (package
+      (name "spacemacs-rolling-release")
+      (version (git-version "0.3.0" "0" commit))
+      (source (origin
+                (method git-fetch)
+                (uri (git-reference
+                      (url "https://github.com/syl20bnr/spacemacs")
+                      (commit commit)))
+                (sha256
+                 (base32
+                  "17yxgchj7qilgljpjai3ad0pzj7k6sq6gqbnxrvcizvkvcnv10z5"))
+                (file-name (string-append name "-" version))
+                (patches
+                 (search-patches
+                  "spacemacs-rolling-release-add-data-dir.patch"
+                  "spacemacs-rolling-release-inhibit-read-only.patch"
+                  "spacemacs-rolling-release-quelpa-permissions.patch"))))
+      (build-system trivial-build-system)
+      (native-inputs `(("tar" ,tar) ("xz" ,xz)))
+      (arguments (list
+                  #:modules '((guix build utils))
+                  #:builder '(begin (use-modules (guix build utils))
+                                    (setenv "PATH"
+                                            (string-append (getenv "PATH") ":"
+                                                           (assoc-ref
+                                                            %build-inputs "xz")
+                                                           "/bin"))
+                                    (mkdir-p (assoc-ref %outputs "out"))
+                                    (system* (string-append
+                                              (assoc-ref %build-inputs "tar")
+                                              "/bin/tar")
+                                             "xf" (assoc-ref %build-inputs
+                                                             "source")
+                                             "-C" (assoc-ref %outputs "out")
+                                             "--strip-components" "1"))))
+      (synopsis "Automatically configured emacs for both emacs and vim users")
+      (description "Spacemacs is a configuration framework for emacs designed to
+work well for people with experience using either emacs or vim.  It has 4
+driving principles: mnemonics, discoverability, consistency, and crowd
+configuration.  Mnemonics mean that key bindings use letters that stand for the
+action they take, making the easier to remember.  Discoverability means that
+help is displayed when partial keybindings are entered, and prepared
+configuration units are searchable.  Consistency means that bindings for
+different use-cases (eg, different programming languages) use the same
+keybindings for similar actions.  And crowd-configuration means that the
+spacemacs community collaborates to provide the best default experience for new
+and expert users alike.")
+      (home-page "https://spacemacs.org")
+      (license license:gpl3))))
+
+(define* (generate-wrapped-emacs-spacemacs emacs spacemacs
+                                           #:optional (name "emacs-spacemacs"))
+  "Given an emacs package and a spacemacs package, create wrappers that allow
+the use of spacemacs without conflicting with the base emacs."
+  (package
+    (name name)
+    (version (string-append (package-version emacs) "-"
+                            (package-version spacemacs)))
+    (source #f)
+    (build-system trivial-build-system)
+    (inputs `(("sh" ,bash)
+              ("emacs" ,emacs)
+              ("spacemacs" ,spacemacs)))
+    (arguments `(#:modules ((guix build utils) (guix build spacemacs-utils))
+                 #:builder (begin
+                             (use-modules ((guix build spacemacs-utils)
+                                           #:prefix spacemacs:))
+                             (spacemacs:builder
+                              #:shell (string-append
+                                       (assoc-ref %build-inputs "sh")
+                                       "/bin/sh")
+                              #:emacs (string-append
+                                       (assoc-ref %build-inputs "emacs")
+                                       "/bin/emacs")
+                              #:spacemacs (assoc-ref %build-inputs "spacemacs")
+                              #:out (string-append
+                                     (assoc-ref %outputs "out") "/bin")))))
+    (home-page (package-home-page spacemacs))
+    (synopsis (package-synopsis spacemacs))
+    (description (package-description spacemacs))
+    (license (package-license spacemacs))))
+
+(define-public emacs-spacemacs
+  (generate-wrapped-emacs-spacemacs emacs spacemacs-rolling-release))
diff --git a/guix/build/spacemacs-utils.scm b/guix/build/spacemacs-utils.scm
new file mode 100644
index 0000000000..5124c41263
--- /dev/null
+++ b/guix/build/spacemacs-utils.scm
@@ -0,0 +1,72 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Bryan Ferris <saffronsnail@protonmail.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build spacemacs-utils)
+  #:use-module (guix build utils)
+  #:use-module (oop goops)
+  #:use-module (srfi srfi-1)
+
+  #:export (builder))
+
+(define (create-initialization-code spacemacs)
+  "Create elisp code that sets spacemacs-specific variables and then loads the
+spacemacs initialization file"
+  (object->string
+   `(progn
+     (setq spacemacs-start-directory (concat ,spacemacs "/"))
+     (setq spacemacs-data-directory
+           (concat (or (getenv "XDG_DATA_DIR")
+                       (concat (getenv "HOME") "/.local/share"))
+                   "/spacemacs/"))
+     (setq package-user-dir (concat spacemacs-data-directory "elpa/"))
+     (load-file (concat spacemacs-start-directory "init.el")))))
+
+(define (generate-wrapper shell output executable . args)
+  "create a shell script interpreted by sh-compatible shell `shell` that
+executes `executable` passing arguments `args` as well as any passed in from
+the command line."
+  (call-with-output-file
+      output (lambda (port)
+               (format port "~A~%~A"
+                       (string-append "#!" shell)
+                       (string-join (list "exec" "-a" shell
+                                          executable (string-join args)
+                                          "\"$@\"")))))
+  (chmod output #o555))
+
+(define* (builder #:key shell emacs spacemacs out)
+  "Create exectables that run emacs, the emacs server, and the emacs client
+with Spacemacs code preloaded."
+  (mkdir-p out)
+
+  (generate-wrapper shell
+                    (string-append out "/spacemacs")
+                    emacs " --no-init-file" "--eval"
+                    (string-append "'"
+                                   (create-initialization-code spacemacs)
+                                   "'"))
+
+  (generate-wrapper shell
+                    (string-append out "/spacemacsdaemon")
+                    (string-append out "/spacemacs")
+                    "--daemon=spacemacs")
+
+  (generate-wrapper shell
+                    (string-append out "/spacemacsclient")
+                    (string-append emacs "client")
+                    "--socket-name" "spacemacs"))
