Close Menu

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    What's Hot

    Oppo Find N6 shown globally with ‘least noticeable foldable crease’

    Motorola to deliver privacy-focused phones by offering GrapheneOS as alternative to Android

    TCL unveils Nxtpaper 70 Pro smartphone with a flicker-free, paper-like display to help minimize headaches and eye strain

    Facebook X (Twitter) Instagram
    • Artificial Intelligence
    • Business Technology
    • Cryptocurrency
    • Gadgets
    • Gaming
    • Health
    • Software and Apps
    • Technology
    Facebook X (Twitter) Instagram Pinterest Vimeo
    Tech AI Verse
    • Home
    • Artificial Intelligence

      What the polls say about how Americans are using AI

      February 27, 2026

      Tensions between the Pentagon and AI giant Anthropic reach a boiling point

      February 21, 2026

      Read the extended transcript: President Donald Trump interviewed by ‘NBC Nightly News’ anchor Tom Llamas

      February 6, 2026

      Stocks and bitcoin sink as investors dump software company shares

      February 4, 2026

      AI, crypto and Trump super PACs stash millions to spend on the midterms

      February 2, 2026
    • Business

      These ultra-budget laptops “include” 1.2TB storage, but most of it is OneDrive trial space

      March 1, 2026

      FCC approves the merger of cable giants Cox and Charter

      February 28, 2026

      Finding value with AI and Industry 5.0 transformation

      February 28, 2026

      How Smarsh built an AI front door for regulated industries — and drove 59% self-service adoption

      February 24, 2026

      Where MENA CIOs draw the line on AI sovereignty

      February 24, 2026
    • Crypto

      Bitcoin Bear Market Could Get Worse Despite the Latest Relief Rally

      March 1, 2026

      Crypto Scammers Have Been Quiet in February, Hacks Fall by 90%

      March 1, 2026

      Vitalik Buterin Signals Major Ethereum Wallet Overhaul

      March 1, 2026

      Why is Hyperliquid Price Rallying Amid the US-Iran War

      March 1, 2026

      Arbitrum Price Under Pressure: 60 Million ARB Whale Sale Sparks ATL Fear

      March 1, 2026
    • Technology

      Oppo Find N6 shown globally with ‘least noticeable foldable crease’

      March 2, 2026

      Motorola to deliver privacy-focused phones by offering GrapheneOS as alternative to Android

      March 2, 2026

      TCL unveils Nxtpaper 70 Pro smartphone with a flicker-free, paper-like display to help minimize headaches and eye strain

      March 2, 2026

      Qi2.2 charging boost

      March 2, 2026

      What if the real risk of AI isn’t deepfakes — but daily whispers?

      March 1, 2026
    • Others
      • Gadgets
      • Gaming
      • Health
      • Software and Apps
    Check BMI
    Tech AI Verse
    You are at:Home»Technology»Writing a basic service for GNU Guix
    Technology

    Writing a basic service for GNU Guix

    TechAiVerseBy TechAiVerseAugust 3, 2025No Comments11 Mins Read2 Views
    Facebook Twitter Pinterest Telegram LinkedIn Tumblr Email Reddit
    Share
    Facebook Twitter LinkedIn Pinterest WhatsApp Email

    Writing a basic service for GNU Guix

    Table of Contents

    • Reading the docs
    • Reading some source
    • Writing kmonad-service-type
    • Using kmonad-service-type
    • A simpler daemon?
    • References

    Let’s write a service for GNU Guix that will automatically start
    kmonad at boot, and keep it running until shutdown.

    Note: before we proceed, we could make a kmonad “daemon” without
    going to the trouble of writing a Guix-specific service: we could
    start kmonad in a shell profile, write a cron job, or something
    else. The user experience of these methods might be the same, but
    writing a service keeps things organized and seems like the “right”
    way. If nothing else, it’s a great learning opportunity.

    Reading the docs

    First let’s read the documentation of GNU Guix. We see that Guix
    offers “services” which extend the functionality of the operating
    system. The manual says:

    Guix system services are connected by extensions. For instance, the
    secure shell service extends the Shepherd—the initialization system,
    running as PID 1—by giving it the command lines to start and stop the
    secure shell daemon (see openssh-service-type); the UPower service
    extends the D-Bus service by passing it its .service specification,
    and extends the udev service by passing it device management rules
    (see upower-service); the Guix daemon service extends the Shepherd by
    passing it the command lines to start and stop the daemon, and extends
    the account service by passing it a list of required build user
    accounts (see Base Services).

    The Guix daemon sounds very similar to what we’re looking to
    construct. Nearby, we see that the Guix daemon defines its own
    “service type”:

    (define guix-service-type
      (service-type
       (name 'guix)
       (extensions
        (list (service-extension shepherd-root-service-type guix-shepherd-service)
              (service-extension account-service-type guix-accounts)
              (service-extension activation-service-type guix-activation)))
       (default-value (guix-configuration))))
    

    Hm. I didn’t expect we’d need to instatiate our own data type just to
    create a simple init daemon. After all, kmonad is simpler than the
    guix daemon – it just needs to start at boot, and that’s it. The
    documentation is terse and it’s not clear whether there’s a better way
    to proceed. Maybe if we find a simple example of service, we can build
    off of it.

    Reading some source

    I saw that “Game Services” were listed in the manual. Maybe there’s a
    simple one we can make a template of. First, we find the definition of
    the games services /gnu/services/games.scm:

    ;;; GNU Guix --- Functional package management for GNU
    ;;; Copyright © 2018 Arun Isaac 
    ;;;
    ;;; 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 .
    
    (define-module (gnu services games)
      #:use-module (gnu services)
      #:use-module (gnu services shepherd)
      #:use-module (gnu packages admin)
      #:use-module (gnu packages games)
      #:use-module (gnu system shadow)
      #:use-module (guix gexp)
      #:use-module (guix modules)
      #:use-module (guix records)
      #:use-module (ice-9 match)
      #:export (wesnothd-configuration
                wesnothd-configuration?
                wesnothd-service-type))
    
    ;;;
    ;;; The Battle for Wesnoth server
    ;;;
    
    (define-record-type* 
      wesnothd-configuration make-wesnothd-configuration wesnothd-configuration?
      (package wesnothd-configuration-package
               (default wesnoth-server))
      (port wesnothd-configuration-port
            (default 15000)))
    
    (define %wesnothd-accounts
      (list (user-account
             (name "wesnothd")
             (group "wesnothd")
             (system? #t)
             (comment "Wesnoth daemon user")
             (home-directory "/var/empty")
             (shell (file-append shadow "/sbin/nologin")))
            (user-group
             (name "wesnothd")
             (system? #t))))
    
    (define wesnothd-shepherd-service
      (match-lambda
        (($  package port)
         (with-imported-modules (source-module-closure
                                 '((gnu build shepherd)))
           (shepherd-service
            (documentation "The Battle for Wesnoth server")
            (provision '(wesnoth-daemon))
            (requirement '(networking))
            (modules '((gnu build shepherd)))
            (start #~(make-forkexec-constructor/container
                      (list #$(file-append package "/bin/wesnothd")
                            "-p" #$(number->string port))
                      #:user "wesnothd" #:group "wesnothd"))
            (stop #~(make-kill-destructor)))))))
    
    (define wesnothd-service-type
      (service-type
       (name 'wesnothd)
       (description
        "Run The Battle for Wesnoth server @command{wesnothd}.")
       (extensions
        (list (service-extension account-service-type
                                 (const %wesnothd-accounts))
              (service-extension shepherd-root-service-type
                                 (compose list wesnothd-shepherd-service))))
       (default-value (wesnothd-configuration))))
    

    There’s only one game contained in (gnu services games) and that is
    The Battle for Wesnoth Server. The Game Services reference says

    To run wesnothd in the default configuration, instantiate it as:

    (service wesnothd-service-type)

    So far, we have a module that exports wesnothd-service-type and a
    way to use that binding in our system config to declare a service.
    Apparently, a new service-type is what we’re looking for after
    all. Let’s start by implementing a kmonad-service-type and see where
    that takes us.

    Writing kmonad-service-type

    A service-type (see Service Reference) takes a name, description,
    and a list of service-extension objects, each of which describes how
    to extend existing services. So what exactly is a
    object? The service-extension documentation
    says:

    Scheme Procedure: service-extension target-type compute

    Return a new extension for services of type target-type. compute must
    be a one-argument procedure: fold-services calls it, passing it the
    value associated with the service that provides the extension; it must
    return a valid value for the target service.

    So in the context of (define kmonad-service-type ...), a compute
    function will receive the (single) value associated with
    kmonad-service-type (a value which we have yet to define) and will
    return the value required by target-type, which is the service being
    extended. The wesnothd-service-type extends two services: the
    account-service-type which is extended by a list of user-group and
    user-account objects; and the shepherd-root-service-type which is
    extended by a list of objects.

    So which services should kmonad extend? It’s recommended to make a
    dedicated user and group for a daemon (see stackoverflow), so let’s
    extend the account-service-type with a new user and group to run the
    kmonad daemon. Let’s also extend the shepherd-root-service-type
    because we want our daemon managed by the init system, Shepherd:

    (define kmonad-service-type
      (service-type
       (name 'kmonad)
       (description
        "Run kmonad as a daemon.")
       (extensions
        (list (service-extension account-service-type
                                 (const %kmonad-daemon-accounts))
              (service-extension shepherd-root-service-type
                                 (compose list kmonad-shepherd-service))))))
    

    It looks pretty similar to wesnothd-service-type, but without the
    default-value, which doesn’t really apply to kmonad. Next, we’ve got
    to choose how to extend the account-service-type and the
    shepherd-root-service-type.

    Extending the account-service-type

    As noted above, (const %kmonad-daemon-accounts) needs to evaluate to a
    function of a single argument that returns a list of users and
    groups. Well, const makes a function that takes some argument, and
    then just returns whatever was passed to const–in this case,
    %kmonad-daemon-accounts. All we’ve got to do is define
    %kmonad-daemon-accounts.

    We need one daemon user and one group. Our daemon user won’t require
    login, so we’ll use /sbin/nologin (see man 8 nologin) like
    %wesnothd-accounts. Similarly, it won’t require a home directory. We
    can pretty much copy the %wesnothd-accounts to make
    %kmonad-daemon-accounts:

    (define %kmonad-daemon-accounts
      (list (user-account
             (name "kmonad-daemon")
             (group "kmonad-daemon")
             (system? #t)
             (comment "kmonad daemon user")
             (home-directory "/var/empty")
             (shell (file-append shadow "/sbin/nologin")))
            (user-group
             (name "kmonad-daemon")
             (system? #t))))
    

    Extending the shepherd-root-service-type

    As noted above, (compose list kmonad-shepherd-service) needs to
    evaluate to a function of a single argument (a single argument of our
    choice) and return a list of objects. That means
    that kmonad-shepherd-service must take a single argument, and return
    a single shepherd-service! Before we write
    kmonad-shepherd-service, let’s decide what we want to pass
    it. Minimally, kmonad needs a .kbd file to run. In theory, a user
    could also specify other stuff (e.g. a log level), but let’s just
    start with the .kbd path.

    If we’re using wesnoth-shepherd-service as an example, we’ll need to
    think about the requirement, start, and stop fields.

    requirement field

    We definitely need to wait for udev, but maybe we should also wait
    for user-processes like the other daemons in the shepherd graph
    do. Looking at the source for user-processes:

    This is a synchronization point used to make sure user processes and daemons
    get started only after crucial initial services have been started—file
    system mounts, etc. This is similar to the ‘sysvinit’ target in systemd.

    In theory we could explicitly wait for other shepherd services, but it
    seems like this catch-all applies perfectly to our use case. Come to
    think of it, I wonder why wesnothd doesn’t depend on
    user-processes too.

    start and stop fields

    According to the Shepherd Services documentation, the start and
    stop fields of shepherd-service take G-Expressions. But what’s a
    g-expression? Well, because Guix uses Scheme for both higher-level
    actions–like defining packages–and lower-level actions–like
    building derivations generated by packages– it needs a faculty for
    embedding lower-level code in higher-level code. So in the start
    field of wesnoth-shepherd-service:

    (start #~(make-forkexec-constructor/container
              (list #$(file-append package "/bin/wesnothd")
                    "-p" #$(number->string port))
              #:user "wesnothd" #:group "wesnothd"))
    

    Some lower-level code is passed with #~(...), within which
    higher-level code is escaped with #$(...) which the compiler is able
    to “lower” to lower-level code. Looking at the source for
    make-forkexec-constructor/container, we see:

    This is a variant of ‘make-forkexec-constructor’ that starts COMMAND in
    NAMESPACES, a list of Linux namespaces such as ‘(mnt ipc). MAPPINGS is the
    list of to make in the case of a separate mount
    namespace, in addition to essential bind-mounts such /proc.

    And the documentation for make-forkexec-contructor reads:

    Return a procedure that forks a child process, closes all file
    descriptors except the standard output and standard error descriptors,
    sets the current directory to directory, sets the umask to
    file-creation-mask unless it is #f, changes the environment to
    environment-variables (using the environ procedure), sets the current
    user to user and the current group to group unless they are #f, and
    executes command (a list of strings.) The result of the procedure will
    be the PID of the child process. Note that this will not work as
    expected if the process “daemonizes” (forks); in that case, you will
    need to pass #:pid-file, as explained below.

    When pid-file is true, it must be the name of a PID file associated
    with the process being launched; the return value is the PID once that
    file has been created. If pid-file does not show up in less than
    pid-file-timeout seconds, the service is considered as failing to
    start.

    When log-file is true, it names the file to which the service’s
    standard output and standard error are redirected. log-file is created
    if it does not exist, otherwise it is appended to.

    The wesnoth source appears not to use the NAMESPACES feature of
    the containerized-version, so we’ll stick with
    make-forkexec-constructor as is used in the syslogd example.

    kmonad-shepherd-service

    Let’s put it all together:

    (define (kmonad-shepherd-service kbd-path)
      (shepherd-service
       (documentation "Run the kmonad daemon (kmonad-daemon)." )
       (provision '(kmonad-daemon))
       (requirement '(udev user-processes))
       (start #~(make-forkexec-constructor
                 (list #$(file-append kmonad "/bin/kmonad")
                       #$kbd-path "-l info")
                 #:user "kmonad-daemon" #:group "kmonad-daemon"
                 #:log-file "/var/log/kmonad.log"))
       (stop #~(make-kill-destructor))))
    

    Making a module

    Now let’s package our code into a module. If the location where we
    keep local guix modules is ~/local-guix, then we can add our module
    at ~/local-guix/my/services/kmonad.scm as:

    (define-module (my services kmonad)
      #:use-module (gnu services)
      #:use-module (gnu services shepherd)
      #:use-module (gnu packages haskell-apps)
      #:use-module (gnu system shadow)
      #:use-module (guix gexp)
      #:export (kmonad-service-type))
    
    (define %kmonad-daemon-accounts
      (list (user-account
             (name "kmonad-daemon")
             (group "kmonad-daemon")
             (system? #t)
             (comment "kmonad daemon user")
             (home-directory "/var/empty")
             (shell (file-append shadow "/sbin/nologin")))
            (user-group
             (name "kmonad-daemon")
             (system? #t))))
    
    (define (kmonad-shepherd-service kbd-path)
      (shepherd-service
       (documentation "Run the kmonad daemon (kmonad-daemon)." )
       (provision '(kmonad-daemon))
       (requirement '(udev user-processes))
       (start #~(make-forkexec-constructor
                 (list #$(file-append kmonad "/bin/kmonad")
                       #$kbd-path "-l info")
                 #:user "kmonad-daemon" #:group "kmonad-daemon"
                 #:log-file "/var/log/kmonad.log"))
       (stop #~(make-kill-destructor))))
    
    (define kmonad-service-type
      (service-type
       (name 'kmonad)
       (description
        "Run kmonad as a daemon.")
       (extensions
        (list (service-extension account-service-type
                                 (const %kmonad-daemon-accounts))
              (service-extension shepherd-root-service-type
                                 (compose list kmonad-shepherd-service))))))
    

    Using kmonad-service-type

    Now adding a kmonad service is straightforward. Let’s add some other
    kmonad-specific configuration to our system while we’re at it:

    (use-modules (my services kmonad))
    ;; more modules
    
    (operating-system
      (users
        (append (list (user-account
                        (supplementary-groups
                          '("input" ;; needed by kmonad
                            ;; more groups
                           ))
                        ;; more fields
                      )
                      ;; more users
                )
                %base-user-accounts))
      (packages
        (append (list
                 "kmonad"
                 ;; more packages
                )
                %base-packages))
      (services
        (append (list (service kmonad-service-type "/path/to/config.kbd")
                      ;; more services
                )
                (modify-services %desktop-services ;; needed to add kmonad udev rules
                  (udev-service-type config =>
                    (udev-configuration (inherit config)
                      (rules (cons kmonad
                        (udev-configuration-rules config))))))))
      ;; more fields
    )
    

    And reconfigure:

    sudo guix system -L ~/local-guix reconfigure /path/to/config.scm
    

    A simpler daemon?

    I think it would be possible to add kmonad as a simple-service on top of
    shepherd-root-service-type. After looking at the simple-service
    source, we can try:

    (simple-service 'kmonad-service shepherd-root-service-type
                    (list (shepherd-service
                           (documentation "Run the kmonad daemon (kmonad-daemon)." )
                           (provision '(kmonad-daemon))
                           (requirement '(udev user-processes))
                           (start #~(make-forkexec-constructor
                                     (list #$(file-append kmonad "/bin/kmonad")
                                           #$kbd-path "-l info")
                                     #:log-file "/var/log/kmonad.log"))
                           (stop #~(make-kill-destructor)))))
    
    

    References

    Share. Facebook Twitter Pinterest LinkedIn Reddit WhatsApp Telegram Email
    Previous ArticleParsing without ASTs and Optimizing with Sea of Nodes [video]
    Next Article Seed7 – The Extensible Programming Language
    TechAiVerse
    • Website

    Jonathan is a tech enthusiast and the mind behind Tech AI Verse. With a passion for artificial intelligence, consumer tech, and emerging innovations, he deliver clear, insightful content to keep readers informed. From cutting-edge gadgets to AI advancements and cryptocurrency trends, Jonathan breaks down complex topics to make technology accessible to all.

    Related Posts

    Oppo Find N6 shown globally with ‘least noticeable foldable crease’

    March 2, 2026

    Motorola to deliver privacy-focused phones by offering GrapheneOS as alternative to Android

    March 2, 2026

    TCL unveils Nxtpaper 70 Pro smartphone with a flicker-free, paper-like display to help minimize headaches and eye strain

    March 2, 2026
    Leave A Reply Cancel Reply

    Top Posts

    Ping, You’ve Got Whale: AI detection system alerts ships of whales in their path

    April 22, 2025701 Views

    Lumo vs. Duck AI: Which AI is Better for Your Privacy?

    July 31, 2025284 Views

    6.7 Cummins Lifter Failure: What Years Are Affected (And Possible Fixes)

    April 14, 2025164 Views

    6 Best MagSafe Phone Grips (2025), Tested and Reviewed

    April 6, 2025124 Views
    Don't Miss
    Technology March 2, 2026

    Oppo Find N6 shown globally with ‘least noticeable foldable crease’

    Oppo Find N6 shown globally with ‘least noticeable foldable crease’ – NotebookCheck.net News ⓘ OppoThe…

    Motorola to deliver privacy-focused phones by offering GrapheneOS as alternative to Android

    TCL unveils Nxtpaper 70 Pro smartphone with a flicker-free, paper-like display to help minimize headaches and eye strain

    Qi2.2 charging boost

    Stay In Touch
    • Facebook
    • Twitter
    • Pinterest
    • Instagram
    • YouTube
    • Vimeo

    Subscribe to Updates

    Get the latest creative news from SmartMag about art & design.

    About Us
    About Us

    Welcome to Tech AI Verse, your go-to destination for everything technology! We bring you the latest news, trends, and insights from the ever-evolving world of tech. Our coverage spans across global technology industry updates, artificial intelligence advancements, machine learning ethics, and automation innovations. Stay connected with us as we explore the limitless possibilities of technology!

    Facebook X (Twitter) Pinterest YouTube WhatsApp
    Our Picks

    Oppo Find N6 shown globally with ‘least noticeable foldable crease’

    March 2, 20262 Views

    Motorola to deliver privacy-focused phones by offering GrapheneOS as alternative to Android

    March 2, 20262 Views

    TCL unveils Nxtpaper 70 Pro smartphone with a flicker-free, paper-like display to help minimize headaches and eye strain

    March 2, 20262 Views
    Most Popular

    7 Best Kids Bikes (2025): Mountain, Balance, Pedal, Coaster

    March 13, 20250 Views

    VTOMAN FlashSpeed 1500: Plenty Of Power For All Your Gear

    March 13, 20250 Views

    Best TV Antenna of 2025

    March 13, 20250 Views
    © 2026 TechAiVerse. Designed by Divya Tech.
    • Home
    • About Us
    • Contact Us
    • Privacy Policy
    • Terms & Conditions

    Type above and press Enter to search. Press Esc to cancel.