# RFE 002: `type = "group"` service for grouping/targeting

## Summary

Add a `type = "group"` (or `"target"`) service kind to zyginit. A
group service has no `[exec]` block; it exists only as a named
synchronization/enable point. Its `[dependencies]` list expands into
the set of services it represents.

This is the equivalent of systemd's `.target` units. It lets admins
enable/disable a feature set with one command without consolidating
unrelated daemons under a single supervisor.

## Motivation

Hammerhead is converting the NFS, IPsec, and zones SMF service sets
to zyginit. NFS in particular spreads across multiple independent
daemons (`nfsmapid`, `statd`, `lockd`, `nfs4cbd`, plus the `client`
mount oneshot) — each with its own lifecycle, restart policy, and
log file.

The natural design is one zyginit service per daemon. But that loses
the SMF-era ergonomics of "enable nfs-client and the dependents come
along". Without a group abstraction we have two bad options:

1. **Combine multiple daemons into one zyginit service.** Cluttered:
   one contract becomes N contracts, restart semantics get fuzzy,
   log routing needs splitting, and the supervisor's child-death
   handling no longer maps 1:1 to a service.

2. **Document the bundle and tell admins to enable each member.**
   Error-prone and ugly:
   ```
   zygctl enable nfs-cbd nfs-mapid nfs-statd nfs-lockd nfs-client
   ```

A group service neatly avoids both:
```toml
[service]
name = "nfs-client"
description = "NFSv4 client services"
type = "group"
[dependencies]
requires = ["nfs-cbd", "nfs-mapid", "nfs-statd", "nfs-lockd",
            "nfs-client-mount"]
```
Then `zygctl enable nfs-client` is sufficient. `zygctl status nfs-client`
reports composite up/down derived from the members.

## Suggested semantics

- `type = "group"` services have no `[exec]` block. The supervisor
  never forks anything for them.
- Status: `running` iff all `requires` members are `running`;
  `stopped` iff none are; `partial` (or `degraded`) if some.
- `zygctl enable <group>` symlinks the group's TOML in `enabled.d/`
  *and* recursively enables each member that is not already enabled
  (or, simpler: refuses unless all members are also enabled —
  consistent with how SMF dependencies block enable today).
- `zygctl disable <group>` is symmetric.
- `zygctl start <group>` / `stop <group>` operate on the member set.
- Cycle detection treats group-edges the same as service-edges.

## Use cases

| Group | Members |
|---|---|
| `nfs-client` | nfs-cbd, nfs-mapid, nfs-statd, nfs-lockd, nfs-client-mount |
| `nfs-server` | nfsd, mountd, nfs-statd, nfs-lockd |
| `zones` | zones, zonestat |
| `audit` | (just `auditd` after the auditset fold-in — not very useful for audit, but harmless) |
| `network-routing` | forwarding, routing/ndp, network-iptun |

Hammerhead would land this in roughly 4–6 group definitions.

## Reporter

Hammerhead build team (Chris Tusa, christusa@gmail.com)
Filed during SMF-to-zyginit migration policy work, 2026-05-08.
