# Extending from shepherd-root-service-type

**URL:** <https://forum.systemcrafters.net/t/extending-from-shepherd-root-service-type/2053>\
**Category:** Guix\
**Created:** [June 12, 2026, 3:42am UTC](https://forum.systemcrafters.net/t/extending-from-shepherd-root-service-type/2053 "2026-06-12T03:42:21Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![aionfork](https://yyz1.discourse-cdn.com/flex029/user_avatar/forum.systemcrafters.net/aionfork/32/1243_2.png) [@aionfork](https://forum.systemcrafters.net/u/aionfork)\
**Post date:** [June 12, 2026, 3:42am UTC](https://forum.systemcrafters.net/t/extending-from-shepherd-root-service-type/2053/1 "2026-06-12T03:42:21Z")

</div>

I’m trying to consolidate some of the references in my source code. I have package names kinda everywhere, so i thought i’d bundle things using `service-type`. However, I’m running into some weird issues as I do

I thought I could just pass service config values to `service-extension`. This is just a record. I figured out how to get past the `udev` issues, but for some reason, nothing I pass as a service extension to `shepherd-root-service-type` gets past `Wrong type to apply`

```scheme
;;; Copyright � 2025 David Conner <aionfork@gmail.com>
(define-module (ellipsis services security-token)
  ;;#:use-module (ellipsis config)
  #:use-module (gnu home services)

  #:use-module (gnu)
  #:use-module (gnu packages)
  #:use-module (gnu packages gnupg)
  #:use-module (gnu packages libusb)
  #:use-module (gnu packages security-token)
  #:use-module (gnu services base)
  #:use-module (gnu services configuration)
  #:use-module (gnu services security-token)
  #:use-module (gnu services shepherd)
  #:use-module (gnu services)

  #:use-module (ellipsis packages golang-crypto)
  #:use-module (ellipsis packages security-token)
  #:use-module (ellipsis packages tls)

  #:use-module (guix gexp)
  #:use-module (guix records)
  #:use-module (srfi srfi-1)
  #:use-module (ice-9 pretty-print)
  #:export (yubikey-udev-rules))

;;; Commentary:
;;;
;;; This module provides a service definition for system services related to
;;; security tokens.

;;;
;;; yubikey-udev-rules
;;;

(define-public yubikey-udev-rules
  ;; needs plugdev, but warns if multiple instantiations create using #:groups
  (list
   (udev-rules-service 'fido2 libfido2 #:groups '("plugdev"))
   (udev-rules-service 'u2f libu2f-host)
   (udev-rules-service 'yubikey yubikey-personalization)))

;; hidapi: HID Devices for FIDO/OTP
(define pkgs-smartcard
  (list opensc pinentry-tty hidapi libu2f-host libfido2))

(define pkgs-yubikey
  (list yubico-piv-tool yubikey-personalization python-yubikey-manager))

(define svc-pcscd
  (service pcscd-service-type))

(define-public ellipsis-smartcard-service-type
  (service-type
   (name 'ellipsis-smartcard)
   (extensions
    (list
     ;; pcsc-lite, ccid provided by service/activation
     (service-extension shepherd-root-service-type svc-pcscd) 
     (service-extension udev-service-type (lambda (config) yubikey-udev-rules))
     (service-extension profile-service-type
                        (lambda (config) (append pkgs-yubikey pkgs-smartcard)))))
   (default-value '())
   (description "Sets up some common services")))
;;; security-token.scm ends here

```

Here’s the error:

```auto
guix/ui.scm:1030:18: Wrong type to apply: #<<service> type: #<service-type pcscd 7ba08bebb800> value: #<<pcscd-configuration> pcsc-lite: #<package pcsc-lite@2.4.1 gnu/packages/security-token.scm:256 7ba090679580> usb-drivers: (#<package ccid@1.7.0 gnu/packages/security-token.scm:105 7ba090679840>)>>

```

In [guix-hpc/guix-hpc-non-free ./hacky/services-gitlab.scm](https://gitlab.inria.fr/guix-hpc/guix-hpc-non-free/-/blob/9f297858106ce7f86b0a3849f9dd720a6863a0b4/hacky/services-gitlab.scm#L127-145), they use:

```scheme
(define gitlab-runner-service-type
  (service-type
   (name 'gitlab-runner)
   (description
    "Run gitlab-runner daemon @command{gitlab-runner run}.")
   (extensions
    (list (service-extension account-service-type
                             (const %gitlab-runner-accounts))
          (service-extension shepherd-root-service-type
                             (compose list gitlab-runner-shepherd-service))
          (service-extension activation-service-type
                             %gitlab-runner-activation)

          ;; 'gitlab-runner' wants to run Git, but since it runs its scripts
          ;; with 'bash --login', PATH is essentially limited to
          ;; /run/current-system/profile/bin. So put Git in there.
          (service-extension profile-service-type
                             (const (list git-minimal)))))
   (default-value (gitlab-runner-configuration))))

```

Where `gitlab-runner-shepherd-service` is a match-lambda, but otherwise returns the result of `(shepherd-service ...)`. What does `compose` do in `(compose list gitlab-runner-shepherd-service)`, specifically?

In other codebases, I often see `(lambda (config) ...)` passed in. It’s a block that returns something that the service-type definition would know how to compose/apply. Why does that not work here?

---

<div class="post-metadata">

**Author:** ![hako](https://yyz1.discourse-cdn.com/flex029/user_avatar/forum.systemcrafters.net/hako/32/1192_2.png) [@hako](https://forum.systemcrafters.net/u/hako)\
**Post date:** [June 12, 2026, 8:49am UTC](https://forum.systemcrafters.net/t/extending-from-shepherd-root-service-type/2053/2 "2026-06-12T08:49:51Z")

</div>

Guix services are different from Shepherd services.

`shepherd-root-service-type` is a type of Guix service, which extends Guix System with the ability to manage daemons.

Take a look at `guix system edit shepherd-root`:

```scheme
(define shepherd-root-service-type
  (service-type
   ...
   (compose concatenate)
   (extend (lambda (config extra-services)
             (shepherd-configuration
               (inherit config)
               (services (append (shepherd-configuration-services config)
                                 extra-services)))))
   (default-value (shepherd-configuration))))

```

The service type accepts a configuration value of `shepherd-configuration`, and can be extended with a list of `shepherd-service` (this is what the `services` field of the `<shepherd-configuration>` record expects).

```scheme
(define-record-type* <shepherd-configuration>
  ...
  (services shepherd-configuration-services
            (default '()))) ; list of <shepherd-service>

```

And the `(service pcscd-service-type)` you used creates a service instance, which is different from both a service type and the shepherd-service we want.

Then take a look at `guix system edit pcscd`:

```scheme
(define pcscd-service-type
  (service-type
   ...
   (extensions
    (list (service-extension shepherd-root-service-type
                             (compose list pcscd-shepherd-service))
          ...))

```

The service type extends `shepherd-root-service-type` with a list of `shepherd-service` created by the `pcscd-shepherd-service` procedure.

(The `pcscd-shepherd-service` procedure is not publicly exported so you can’t refer to it normally, and is not very useful for your use case, since it’s closely tied to the implementation of `pcscd-service-type`)

BTW the `udev-rules-service` defines service types which are not expected for extending `udev-service-type`. The service type should be extended by a list of file-like objects, like packages.

* * *

To address your issue, you can either

extend `shepherd-root-service-type` with a list of `shepherd-service`, then extend `udev-service-type` and `account-service-type` (that’s how the `#:groups` keyword is implemented) like what `udev-rules-service` does.

I recommend learning it if you have time, the service part of Guix is quite interesting.

or

instantiate service instance without explicitly defining a service type via `simple-service`:

```scheme
(service pcscd-service-type)

(udev-rules-service 'fido2 libfido2 #:groups '("plugdev"))
(udev-rules-service 'u2f libu2f-host)
(udev-rules-service 'yubikey yubikey-personalization)

(simple-service 'ellipsis-smartcard-profile-service
                profile-service-type
                (append pkgs-yubikey pkgs-smartcard))

```

In this approach you can also organize these service instances as a list and append it into your operating system declaration.

---

<div class="post-metadata">

**Author:** ![aionfork](https://yyz1.discourse-cdn.com/flex029/user_avatar/forum.systemcrafters.net/aionfork/32/1243_2.png) [@aionfork](https://forum.systemcrafters.net/u/aionfork)\
**Post date:** [June 12, 2026, 9:15am UTC](https://forum.systemcrafters.net/t/extending-from-shepherd-root-service-type/2053/3 "2026-06-12T09:15:46Z")

</div>

thanks, i appreciate the writeup. i think a list of services is about as simple as i can get it.
