Folds
A fold is a label, nothing more. It doesn't isolate a sheep's filesystem, network, or resources. It just gives a group of sheep a name you can select, list, and read off the flock table, sobackend and jobs don't have to be regexes you keep retyping.
Setting one
Add fold = "<name>" to any app in a Flockfile. A sheep with no fold field simply has none. It prints- in the table and null under--format json.
[[app]] name = "web" script = "./server" fold = "backend" [[app]] name = "worker" script = "./worker" fold = "backend" [[app]] name = "cron" script = "./cron" fold = "jobs"
Listing one
shep fold <name> lists exactly that fold. Nothing else in the flock. It's shep flock pre-filtered, plus one thing the plain flock table never shows: a Lambssection under any sheep that has spawned children of its own, one per sheep, listing every parent-pid descendant by PID and name:
$ shep fold backend ID NAME STATUS PID RESTARTS CPU MEM UPTIME FOLD 0 web online 64778 0 - 4.2M 1s backend 1 worker online 64782 0 - 4.2M 1s backend Lambs of web (id 0) — parent-pid descendants of 64778, which is not exactly the set a stop kills PID NAME 64780 sleep 64781 sleep Lambs of worker (id 1) — parent-pid descendants of 64782, which is not exactly the set a stop kills PID NAME 64784 sleep 64785 sleep
A sheep with no children of its own gets no Lambs section at all. The two above both happen to fork workers, which is why both get one. SeeJSON output for how the same data surfaces as the lambs array under --format json.
A fold name that matches nothing is the same not_founderror any other selector gives you, exit code 3, not an empty list:
$ shep fold nonexistent error[not_found]: the daemon reported NotFound: selector matched no registered sheep
Selecting one from any verb
Every verb accepts fold:<name> in place of a name, an id, a /regex/, a glob, name:slot(web:2, one instance of a multi-instance app), orall. That is stop, restart,reload, delete, bleats,trigger, start, and the rest. It reaches every sheep carrying that fold in one call:
$ shep stop fold:backend ID NAME STATUS PID RESTARTS EXIT CPU MEM UPTIME FOLD SMIT 2 cron online 16564 0 - - 32.0K 0s - - 0 web stopped - 0 SIGTERM - - 0s backend - 1 worker stopped - 0 SIGTERM - - 0s backend -
The listing is the whole flock, not just the fold. Every lifecycle verb prints it that way, so cron is there and still online. Seeterminal output.
Folds on start
shep start takes selectors like every other verb, and it also takes the things only it can take: a script path, a Flockfile, or- for Flockfile JSON on stdin. That makes some targets ambiguous, so it resolves one in a fixed order and the first tier that matches wins.
fold:backed, or just backedSo shep start backed starts the fold even when a file called backed is sitting right there in the current directory. Write ./backed when you mean the file. That works whatever your sheep are called: a sheep name may never contain a path separator, so a target carrying one is always a path.
Only sheep the flock already has can be reached this way. A fold is a field on a registered sheep, so there is nothing for a fold to register. A sheep that is already running is reported and left alone;restart is the verb that replaces one.
$ shep start fold:backed ID NAME STATUS PID RESTARTS EXIT CPU MEM UPTIME FOLD SMIT 0 golbat online 19303 1 - - 32.0K 0s backed - 1 koji online 19304 1 - - 32.0K 0s backed - 2 rotom online 19260 0 - - 32.0K 0s front - $ shep start fold:typo error[not_found]: no sheep is in a fold called typo
A selector that matched nothing is not_found, exit 3, the same as everywhere else. It does not fall back to looking for a file called fold:typo.
Selector parsing checks shapes in a fixed order, and it matters if a name is ambiguous with something else: the literal wordall, then a fold: prefix, then/regex/ slashes, then (if the whole string is ASCII digits) a numeric id, then a glob, then name:slot. Only after all six fail does it fall back to treating the string as a plain name. A sheep named 2 is the practical edge of this: typing 2 as a selector always means "id 2", never "the sheep named 2", even if those aren't the same sheep. fold:names don't collide with any of this: the prefix is checked for before/regex/ or a bare number, so a fold can be named anything, including all or a number, andfold:<that name> still reaches it. A glob likeweb* is checked before name:slot, so it still matches every instance of an app rather than being read as a name with a stray colon; and since a colon is no longer legal in a sheep name at all, web:2 can only ever mean slot 2 of web, never a literal name.
What a fold is not
Folds carry no uniqueness constraint and no nesting: a name is a flat string, and two sheep can share one with nothing else in common. There is no shep fold create or config listing every fold that exists; a fold exists exactly as long as some sheep'sfold field names it, and disappears the moment the last one does. If you're picturing folds as something closer to a Kubernetes namespace or a cgroup, that's the wrong mental model. The closest real comparison is a tag.