Hi Guix,

I’d like to float an idea for a new subcommand I have been thinking of developing, guix session, and get feedback on whether this is something that would make sense in Guix proper, or should live as an external
tool.

The basic motivation: many projects end up with long guix time-machine /
guix shell incantations stashed in a README or Makefile. These are
powerful, but they can be hard to remember and type, be slightly
different in every project, are not easily introspectable from Scheme,
and rarely produce any reusable “provenance artifact” of what was
actually run.

The proposal is to give that pattern a first-class, Scheme-native
representation in Guix, in the same spirit as manifest.scm and
channels.scm.

Today a project might say:

guix time-machine -C channels.scm -- shell \
   -m manifest-dev.scm \
   --container --no-cwd \
   --share="$PWD=/workspace" \
   --preserve='^TERM$' \
   --preserve='^LANG$' \
   --preserve='^EDITOR$' \
   -- /bin/sh -lc 'cd /workspace && exec "$SHELL"'

This pins Guix, sets up a container, mounts the project at /workspace, preserves a few useful environment variables, and then drops you into a
shell in the right directory.

With guix session, the same environment could be entered with:

guix session shell dev
or
guix session shell -f session.scm -s dev

Where dev is the name of a session defined in a project-local
session.scm file.

Here is a minimal example of such a file:

;; session.scm
;;
;; Evaluates to a list of session records.
;; Module names and record names here are illustrative.

(use-modules
 (guix session)) ; hypothetical module

(list
 (session
   (name "dev")

   ;; guix time-machine -C channels.scm
   (channels-file "channels.scm")

   ;; shell -m manifest-dev.scm
   (manifests '("manifest-dev.scm"))

   ;; shell --container
   (container? #t)

   ;; --share="$PWD=/workspace"
   (mounts
     (list
       (mount
         (host ".")               ; project root
         (target "/workspace")
         (writable? #t))))

   ;; where to land inside the session
   ;; (implemented with cd/exec or a future --chdir flag)
   (workdir "/workspace")

;; env-allow/env-set translate to environment + --preserve=… flags
   (env-allow '("TERM" "LANG"))
   (env-set   '(("EDITOR" . "emacs")))))

The intent is that guix session shell dev is equivalent to the long guix
time-machine ... shell command above, but expressed as Scheme data
instead of ad-hoc shell.

The session file can contain multiple such sessions, e.g. "dev", "ci",
"release", etc., all in one place.

Why not just use a Makefile? It’s true that a Makefile can get you quite
far:

dev:
        guix time-machine -C channels.scm -- \
          shell -m manifest-dev.scm --container --no-cwd \
            --share="$PWD=/workspace" \
--preserve='^TERM$$' --preserve='^LANG$$' --preserve='^EDITOR$$' \
            -- /bin/sh -lc 'cd /workspace && exec "$$SHELL"'

A session.scm file, however, is declarative. Guix and other tools can inspect and manipulate it from Scheme. With session.scm and guix session
there is a standard entry point:

guix session shell           # use default session
guix session shell dev
guix session run ci -- make test
guix session inspect

A newcomer doesn’t have to guess whether the target is dev, shell, env,
etc. across projects; the interface is the same.

One nice consequence of having a structured session is the ability to record a session snapshot each time you run: the original (session ...) record, the resolved channels commit used by time-machine, the final
command, exit code, timestamp, etc.

Such a snapshot could itself be a Scheme record, and be re-usable:

guix session run --file=session-snapshot-2025-02-01.scm

Before I spend time turning this into working code, I’d really
appreciate any feedback.

Is this something you would consider in-scope for Guix? Or does it feel like it should live as an external, Guile-based helper script instead?

Is the name session the best choice with session.scm as the conventional filename in a project root (analogous to manifest.scm and channels.scm)?

Are the fields above the right level of abstraction?

Any obvious things missing or that should be left out?

Do people already do something very similar that I should be aware of?

If there’s interest, I’d plan to prototype this as an out-of-tree Guile
script first (guix-session), and only then discuss integrating it
properly as (guix scripts session) / (guix session) with tests and
documentation.

I’d be grateful for any comments, design criticism, or “this is a bad
idea because…” feedback.

Peter

Reply via email to