 
 ;;;###autoload
 (defun +workspace-list ()
-  "Retrieve a list of names of open workspaces (strings)."
+  "Return a list of workspace structs."
+  (mapcar #'persp-get-by-name (+workspace-list-names)))
+
+;;;###autoload
+(defun +workspace-list-names ()
+  "Return a list of workspace names (strings)."
   (delete persp-nil-name (persp-names-current-frame-fast-ordered)))
+
+;;;###autoload
+(defun +workspace-buffer-list (&optional persp)
+  "Return a list of buffers in PERSP (defaults to the current perspective).
+
+PERSP can be a string (name of a workspace) or a perspective hash (satisfies
+`+workspace-p').
+
+If PERSP is t, then return a list of orphaned buffers associated with no
+perspectives."
+  (cond ((not persp)
+         (persp-buffer-list-restricted))
+        ((eq persp t)
+         (cl-remove-if #'persp--buffer-in-persps (doom-buffer-list)))
+        ((+workspace-p persp)
+         (safe-persp-buffers persp))
+        ((stringp persp)
+         (safe-persp-buffers (+workspace-get persp t)))))
 
 ;;;###autoload
 (defun +workspace-p (obj)

    (setq name (symbol-name name)))
  (unless (stringp name)
    (error "Expected a string, got a %s" (type-of name)))
  (member name (+workspace-list)))

;;;###autoload
(defun +workspace-get (name &optional noerror)

end of the workspace list."
  (interactive
   (list (or current-prefix-arg
             (completing-read "Switch to workspace: " (+workspace-list-names)))))
  (when (and (stringp index)
             (string-match-p "^[0-9]+$" index))
    (setq index (string-to-number index)))
  (condition-case ex
      (let ((names (+workspace-list-names))
            (old-name (+workspace-current-name)))
        (cond ((numberp index)
               (let ((dest (nth index names)))
