@sous-io/sous 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/markdown/README.md +4 -0
- package/docs/markdown/_sidebar.md +4 -1
- package/docs/markdown/commands.md +293 -274
- package/docs/markdown/configuration.md +7 -0
- package/docs/markdown/repositories-authoring.md +210 -302
- package/docs/markdown/repositories-consuming.md +219 -468
- package/docs/markdown/repositories-file-formats.md +216 -980
- package/docs/markdown/repositories-providers.md +322 -0
- package/docs/markdown/repositories-quickstart.md +340 -0
- package/docs/markdown/repositories-troubleshooting.md +336 -0
- package/docs/markdown/repositories-variables.md +229 -296
- package/docs/markdown/repositories.md +262 -228
- package/package.json +1 -1
- package/recipes/core/sous-skills/sous.recipe.yaml +1 -1
|
@@ -1,205 +1,286 @@
|
|
|
1
1
|
# Repositories
|
|
2
2
|
|
|
3
3
|
A **repository** publishes shared agent configuration that any project can subscribe to. It is
|
|
4
|
-
an ordinary git repository holding a few manifest files and some markdown, and sous reads it
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
an ordinary git repository holding a few manifest files and some markdown, and sous reads it the
|
|
5
|
+
way a package manager reads a registry: an index says what exists, a project says what it wants,
|
|
6
|
+
and a lockfile records exactly what it got.
|
|
7
7
|
|
|
8
|
-
This page
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
[Repository file formats](repositories-file-formats.md).
|
|
8
|
+
This page is the map: the vocabulary the system is built from, the official repository every
|
|
9
|
+
project starts with, how a single build fits them together, and where every file lands on disk.
|
|
10
|
+
The task-oriented guides are listed at the bottom.
|
|
12
11
|
|
|
13
|
-
##
|
|
12
|
+
## The vocabulary
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
### Repositories
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
versioned, and a project can subscribe to a whole namespace at once.
|
|
21
|
-
- A **recipe** is the unit you subscribe to and the unit that carries a version. It may hold
|
|
22
|
-
skills, memories, prompts, config layers, variable definitions, or any mixture of them.
|
|
23
|
-
Subscribing to a recipe gets everything in it.
|
|
16
|
+
A repository is the unit of distribution and the unit of trust; you add one to a project, and
|
|
17
|
+
everything else flows from that. Its root holds `sous.repo.yaml`, which names the repository,
|
|
18
|
+
describes its namespaces and lists where its recipes live.
|
|
24
19
|
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
```yaml
|
|
21
|
+
# sous.repo.yaml
|
|
22
|
+
formatVersion: 1
|
|
23
|
+
name: agent-recipes
|
|
24
|
+
namespaces:
|
|
25
|
+
workflow:
|
|
26
|
+
description: Recipes about how work moves through a project.
|
|
27
|
+
recipes:
|
|
28
|
+
- recipes/workflow/task-files
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Namespaces
|
|
32
|
+
|
|
33
|
+
A namespace groups related recipes inside one repository. It is a plain name, it is never
|
|
34
|
+
versioned, and a project can subscribe to a whole namespace in one command.
|
|
35
|
+
|
|
36
|
+
```term
|
|
37
|
+
$ sous namespace list
|
|
38
|
+
▶ Namespaces in the repositories this project trusts:
|
|
39
|
+
|
|
40
|
+
Namespace Repository Recipes Subscribed What it is
|
|
41
|
+
---------- ---------- ------- ---------- ------------------------------------------
|
|
42
|
+
quality qa 2 no Recipes that exercise the edges.
|
|
43
|
+
workflow qa 2 no Recipes about how work moves.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Recipes
|
|
47
|
+
|
|
48
|
+
A recipe is the unit you subscribe to and the only thing that carries a version. It may hold
|
|
49
|
+
skills, memories, prompts, config layers and variable definitions in any mixture, and
|
|
50
|
+
subscribing to it gets all of them.
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
# recipes/workflow/task-files/sous.recipe.yaml
|
|
54
|
+
formatVersion: 1
|
|
55
|
+
namespace: workflow
|
|
56
|
+
name: task-files
|
|
57
|
+
version: 1.0.2
|
|
58
|
+
contents:
|
|
59
|
+
- kind: skills
|
|
60
|
+
include:
|
|
61
|
+
- skills/**/*.md
|
|
32
62
|
```
|
|
33
63
|
|
|
34
64
|
A recipe is named by a **ref**: `workflow` for a whole namespace, `workflow/task-files` for one
|
|
35
65
|
recipe, `workflow/task-files@^1.2.0` to constrain the version, and
|
|
36
|
-
`sous-recipes:workflow/task-files` when two
|
|
37
|
-
needs to be told which one you meant.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
`sous-recipes:workflow/task-files` when two trusted repositories publish the same ref and sous
|
|
67
|
+
needs to be told which one you meant. A one-word ref is a guess at a name, and sous works it out:
|
|
68
|
+
a namespace first, a recipe second, across every repository the project trusts. The full grammar
|
|
69
|
+
is in [Refs: how anything is named](repositories-file-formats.md#refs-how-anything-is-named).
|
|
70
|
+
|
|
71
|
+
### Subscriptions
|
|
72
|
+
|
|
73
|
+
A subscription is your project saying it wants a recipe or a namespace. It is recorded in a
|
|
74
|
+
config layer sous writes, `.sous/conf.d/510-subscriptions.jsonc`, so it is committed and travels
|
|
75
|
+
with the project.
|
|
76
|
+
|
|
77
|
+
```jsonc
|
|
78
|
+
{
|
|
79
|
+
"subscriptions": {
|
|
80
|
+
"workflow/task-files": {
|
|
81
|
+
"addedAt": "2026-09-12T07:01:30.123Z",
|
|
82
|
+
"addedBy": "user"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Dependencies
|
|
89
|
+
|
|
90
|
+
A recipe manifest can declare two relationships to other recipes, and they differ in exactly one
|
|
91
|
+
respect: whose files end up in your project. `depends` fetches, pins and trust-gates the target
|
|
92
|
+
and makes it addressable while rendering, but keeps its files out of your output; `subscribes`
|
|
93
|
+
does all of that and lands the target's files in your project too, along with the variable
|
|
94
|
+
questions it publishes (see [Recipe variables](repositories-variables.md)).
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
depends:
|
|
98
|
+
- workflow/qa-helper # a sibling in this repository
|
|
99
|
+
- github://sous-io/sous-recipes/workflow/task-files@^1.0 # one in another repository
|
|
100
|
+
subscribes:
|
|
101
|
+
- quality/code-review
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Both name their targets by location, written as a **locator URL**
|
|
105
|
+
([the grammar](repositories-file-formats.md#dependencies-named-by-location)) when the target lives
|
|
106
|
+
in another repository, never by a short name a consuming project chose; a curated bundle is simply
|
|
107
|
+
a recipe made mostly of `subscribes` entries. Because both lists are
|
|
108
|
+
declarative YAML rather than code, sous can read the whole dependency closure before fetching any
|
|
109
|
+
of it, which is what makes the trust decision answerable up front.
|
|
110
|
+
|
|
111
|
+
### The lockfile
|
|
112
|
+
|
|
113
|
+
`.sous/sous.lock.json` records the exact version, content hash and holder of everything the
|
|
114
|
+
project uses. It is committed, and a fresh clone rebuilds precisely what it describes.
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"formatVersion": 1,
|
|
119
|
+
"recipes": {
|
|
120
|
+
"workflow/qa-helper": {
|
|
121
|
+
"hash": "sha256-78660ab9889e707a38befd193ad565f7d76fbf017e049f1ae87372bb2c69698d",
|
|
122
|
+
"kind": "subscribes",
|
|
123
|
+
"repo": "qa",
|
|
124
|
+
"requestedBy": ["project"],
|
|
125
|
+
"version": "0.1.0"
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"repos": {
|
|
129
|
+
"qa": { "identity": "localhost/home/me/projects/qa", "url": "/home/me/Projects/qa" }
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Restore decides nothing: it never resolves a range, never picks a newer version and never
|
|
135
|
+
prompts. Anything that would change what is installed changes the lockfile first, as a diff you
|
|
136
|
+
can read in review.
|
|
137
|
+
|
|
138
|
+
### The store
|
|
139
|
+
|
|
140
|
+
The store is one machine-wide cache of fetched recipes, at `~/.sous/cache`, keyed by the
|
|
141
|
+
repository's identity rather than by the short name any one project gave it. It is disposable:
|
|
142
|
+
every entry is re-fetchable from the pins in some project's lockfile, so deleting it costs a
|
|
143
|
+
download and nothing else.
|
|
144
|
+
|
|
145
|
+
```text
|
|
146
|
+
~/.sous/cache/github.com/sous-io/sous-recipes/core/sous-skills/0.2.0/
|
|
147
|
+
~/.sous/cache/_indexes/github.com/sous-io/sous-recipes.json
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`sous repo gc` collects the store back to a size cap, least recently used first, never evicting
|
|
151
|
+
an entry the lockfile of the project you run it in still pins; entries another project pins may
|
|
152
|
+
go, because they are re-fetchable from that project's lockfile.
|
|
153
|
+
|
|
154
|
+
### Trust
|
|
155
|
+
|
|
156
|
+
Adding a repository **is** trusting it. There is no separate trust command and no
|
|
157
|
+
trusted-but-not-added state: until a repository is added, sous downloads nothing from it, not
|
|
158
|
+
even its index.
|
|
64
159
|
|
|
65
160
|
```term
|
|
66
|
-
$ sous repo add https://github.com/
|
|
161
|
+
$ sous repo add https://github.com/my-team/agent-recipes
|
|
67
162
|
// sous prints the repository, its location and what trusting it means
|
|
68
163
|
Do you trust this repository? (y/N)
|
|
69
164
|
```
|
|
70
165
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
166
|
+
Trusting a repository trusts every namespace and recipe in it, including recipes published later,
|
|
167
|
+
and it is the last gate before a recipe can run scripts on your machine; sous cannot tell you
|
|
168
|
+
whether one deserves that, and says so rather than implying otherwise. Where there is no terminal
|
|
169
|
+
to ask on, the run fails and names the repositories and the exact command that grants the trust:
|
|
75
170
|
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
|
|
171
|
+
```text
|
|
172
|
+
Error: One repository has to be trusted before this can continue, and sous is not
|
|
173
|
+
running where it can ask.
|
|
174
|
+
Why: the '--non-interactive' flag was passed.
|
|
175
|
+
|
|
176
|
+
agent-recipes: https://github.com/my-team/agent-recipes
|
|
177
|
+
agent-recipes (required by project)
|
|
178
|
+
|
|
179
|
+
Trusting a repository trusts every namespace and recipe in it, and
|
|
180
|
+
subscribing to something inside it can run scripts on this machine.
|
|
181
|
+
Add each repository deliberately, with its URL:
|
|
79
182
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
nothing new enters a project except through an explicit, visible change to files under version
|
|
83
|
-
control.
|
|
183
|
+
sous repo add https://github.com/my-team/agent-recipes --name agent-recipes --trust
|
|
184
|
+
```
|
|
84
185
|
|
|
85
|
-
!> Trust semantics do not soften for a repository
|
|
86
|
-
|
|
87
|
-
|
|
186
|
+
!> Trust semantics do not soften for a repository already on your disk. A local path added
|
|
187
|
+
through the `local` provider goes through the same ceremony, because its recipes still run on
|
|
188
|
+
this machine.
|
|
88
189
|
|
|
89
|
-
## The official repository, and
|
|
190
|
+
## The official repository, and the built-in core
|
|
90
191
|
|
|
91
192
|
Sous publishes one official repository, [`sous-io/sous-recipes`](https://github.com/sous-io/sous-recipes).
|
|
92
193
|
Its namespaces are drawn from the canonical [skill categories](skill-categories.md), plus one
|
|
93
194
|
extra namespace called `core`.
|
|
94
195
|
|
|
95
|
-
`core` is the exception
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
seeds the machine-wide store on first run. A fresh install therefore works with no network at
|
|
101
|
-
all, and the release pipeline pushes the same content to the official repository under the same
|
|
102
|
-
version number, so the built-in copy and the published copy are the same bytes.
|
|
196
|
+
`core` is the exception. It holds the skills that teach an agent what sous is, why generated files
|
|
197
|
+
must not be hand-edited and where the source of a managed file lives; without them an agent will
|
|
198
|
+
cheerfully edit a compiled `CLAUDE.md`. So the official repository is added and `core` is
|
|
199
|
+
subscribed in every project, pinned to the sous CLI version you are running, and its source ships
|
|
200
|
+
inside the package and seeds the store on first run, so a fresh install needs no network at all.
|
|
103
201
|
|
|
104
|
-
|
|
202
|
+
```term
|
|
203
|
+
$ sous subscription list
|
|
204
|
+
▶ Subscriptions:
|
|
105
205
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
core
|
|
109
|
-
|
|
206
|
+
Subscription Range Pinned version Origin Enabled
|
|
207
|
+
------------------ ----------- ------------------------ -------- -------
|
|
208
|
+
core 0.2.0 core/sous-skills 0.2.0 built in yes
|
|
209
|
+
workflow/qa-helper any version workflow/qa-helper 0.1.0 user yes
|
|
110
210
|
```
|
|
111
211
|
|
|
112
|
-
|
|
113
|
-
`sous subscription remove core`
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
repositories, especially a team repository whose namespace is genuinely one coherent set. In the
|
|
117
|
-
official repository they are not what you want: any arrangement of its content yields either
|
|
118
|
-
one-recipe namespaces or a namespace of unrelated recipes, so subscribe to official recipes one
|
|
119
|
-
at a time. `core` is the deliberate exception.
|
|
212
|
+
Both wirings are ordinary config entries a person could have written by hand, and either can be
|
|
213
|
+
switched off: `sous subscription remove core` writes `subscriptions.core.enabled: false` for you,
|
|
214
|
+
and `sous subscription add core` clears it again. See
|
|
215
|
+
[Opt out of `core`](repositories-consuming.md#opt-out-of-core) for what you give up.
|
|
120
216
|
|
|
121
|
-
|
|
217
|
+
?> Subscribe to a whole namespace when it is one coherent set your team owns end to end. In the
|
|
218
|
+
official repository, prefer subscribing to recipes one at a time, so a recipe published later
|
|
219
|
+
does not arrive in your project unasked. `core` is the deliberate exception.
|
|
122
220
|
|
|
123
|
-
|
|
124
|
-
is exactly one thing: whose files end up in your project.
|
|
221
|
+
## One build, end to end
|
|
125
222
|
|
|
126
|
-
|
|
127
|
-
|--------------|--------------------|-------------|---------------------------------------|--------------------------|
|
|
128
|
-
| `depends` | yes | yes | yes | no |
|
|
129
|
-
| `subscribes` | yes | yes | yes | yes |
|
|
223
|
+
Four steps take a team repository from nothing to compiled skills.
|
|
130
224
|
|
|
131
|
-
|
|
132
|
-
reads while rendering its own files. `subscribes` is a co-subscription: subscribing to the recipe
|
|
133
|
-
subscribes your project to the listed targets with full semantics, so their questions run and
|
|
134
|
-
their files land in your output. A curated bundle is simply a recipe made mostly of `subscribes`
|
|
135
|
-
entries; there is no special bundle type.
|
|
225
|
+
**Add the repository**, which asks you to trust it and fetches its index, nothing more:
|
|
136
226
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
227
|
+
```term
|
|
228
|
+
$ sous repo add https://github.com/my-team/agent-recipes
|
|
229
|
+
▶ Adding a repository:
|
|
230
|
+
Repository: agent-recipes
|
|
231
|
+
Location : https://github.com/my-team/agent-recipes
|
|
232
|
+
Provider : github
|
|
233
|
+
Namespaces: quality, workflow
|
|
234
|
+
Recipes : 4
|
|
235
|
+
This project now trusts 'agent-recipes'. Nothing from it has been installed.
|
|
236
|
+
```
|
|
146
237
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
code would break that, which is why manifests are YAML or JSON and never JavaScript.
|
|
238
|
+
**Subscribe to a recipe.** Sous resolves the dependency closure, shows what it will install,
|
|
239
|
+
asks about any repository a dependency needs that you have not trusted, records the subscription
|
|
240
|
+
and the pins, then builds:
|
|
151
241
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
242
|
+
```term
|
|
243
|
+
$ sous subscription add workflow/task-files
|
|
244
|
+
➔ What was installed:
|
|
245
|
+
Recipe Version Repository Why
|
|
246
|
+
------------------- ------- ------------- ----------------------
|
|
247
|
+
workflow/task-files 1.0.2 agent-recipes you subscribed to it
|
|
248
|
+
➔ Lockfile:
|
|
249
|
+
Adding workflow/task-files version 1.0.2
|
|
250
|
+
```
|
|
155
251
|
|
|
156
|
-
|
|
252
|
+
**Answer the questions** the recipe publishes. A question is asked only when a subscribed recipe
|
|
253
|
+
needs a variable and no valid answer is already in scope, and the answers land in this project's
|
|
254
|
+
env files. See [Recipe variables](repositories-variables.md).
|
|
157
255
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
rebuilds precisely what the lockfile describes, fetching those versions and no others, and asking
|
|
161
|
-
nothing:
|
|
256
|
+
**Build.** Every later build reads the pins, restores anything missing from the store, then
|
|
257
|
+
compiles the recipe's files into your project's agent directories alongside your own templates:
|
|
162
258
|
|
|
163
259
|
```term
|
|
164
|
-
$ git clone git@github.com:my-team/my-project.git
|
|
165
|
-
>> 100%
|
|
166
260
|
$ sous build
|
|
167
|
-
Restoring recipes
|
|
261
|
+
▶ Restoring recipes:
|
|
168
262
|
This project's lockfile pins recipes that are not in the store on this machine,
|
|
169
|
-
|
|
170
|
-
|
|
263
|
+
so they are being fetched at exactly the versions it records.
|
|
264
|
+
restored: workflow/task-files
|
|
265
|
+
▶ Building:
|
|
266
|
+
▷ SKILL.tpl.md:
|
|
267
|
+
Entry Point: ~/.sous/cache/github.com/my-team/agent-recipes/workflow/task-files/1.0.2/skills/start-task/SKILL.tpl.md
|
|
268
|
+
✓ /home/me/my-project/.claude/skills/start-task/SKILL.md (~1,996 tokens)
|
|
171
269
|
```
|
|
172
270
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
can read in review.
|
|
176
|
-
|
|
177
|
-
## Providers
|
|
271
|
+
Skills default to `<project root>/.claude/skills`; every other content kind needs a destination in
|
|
272
|
+
the [`recipeOutputs`](repositories-file-formats.md#recipeoutputs-where-the-files-land) block.
|
|
178
273
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
A
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
itself, fork it onto your account, and open the proposal. Each call answers with plain data, so
|
|
190
|
-
the command driving it never learns what tool ran.
|
|
191
|
-
|
|
192
|
-
Each provider declares the features it really has, `fetch` and `submit`, and sous consults that
|
|
193
|
-
list rather than a provider's name. `local` declares `fetch` only: a repository on your own disk
|
|
194
|
-
is edited directly, so asking sous to propose a change to it is refused with a message naming the
|
|
195
|
-
provider and the feature. A provider that supports a feature only partly says so plainly rather
|
|
196
|
-
than guessing; GitLab, for instance, reports that it cannot tell whether you may push instead of
|
|
197
|
-
sending you down a fork path it cannot finish.
|
|
198
|
-
|
|
199
|
-
?> Adding a provider is one file. A class extending `ProviderBase` inherits the subprocess, token
|
|
200
|
-
and refusal plumbing, implements the read path, declares its features, and overrides the write
|
|
201
|
-
calls it supports; adding it to the built-in list is the only other change. The interface is
|
|
202
|
-
internal for now, not a published plugin API.
|
|
274
|
+
By default a build uses what the lockfile pins and does not talk to the network. Two things
|
|
275
|
+
change that: **always-pull**, which installs a newer in-range version whenever one exists, and
|
|
276
|
+
the **freshness window** (`store.freshnessSeconds`, five minutes by default), which decides how
|
|
277
|
+
often sous looks upstream at all. A failed check never breaks a build; the last good index stands
|
|
278
|
+
and the build says so. See
|
|
279
|
+
[Control freshness and the store](repositories-consuming.md#control-freshness-and-the-store).
|
|
280
|
+
A **linked** repository sits outside all of it: `sous repo link` points one repository's
|
|
281
|
+
resolution at a working copy on your machine, bypassing versions, the lockfile and freshness
|
|
282
|
+
checks, so every build announces it loudly. See
|
|
283
|
+
[Edit a repository in place](repositories-authoring.md#edit-a-repository-in-place).
|
|
203
284
|
|
|
204
285
|
## Where everything lives
|
|
205
286
|
|
|
@@ -216,88 +297,41 @@ internal for now, not a published plugin API.
|
|
|
216
297
|
| `~/.sous/sous.links.json` | the machine-wide links map | not in a project at all |
|
|
217
298
|
|
|
218
299
|
The user-level directory is `~/.sous`, and `SOUS_HOME` moves it. Unlike `SOUS_CONFIG` and
|
|
219
|
-
`SOUS_DIR`,
|
|
220
|
-
`.sous/.env
|
|
221
|
-
|
|
222
|
-
The three files in the `500` to `599` band are written by sous, and the band exists precisely so
|
|
223
|
-
that machine-written layers never collide with the config you wrote. Sous edits them by key, so
|
|
224
|
-
your comments, your key order and your formatting survive a write, and you may edit them
|
|
225
|
-
yourself. Sous never edits your primary config. You may
|
|
226
|
-
hand-write `repos:`, `subscriptions:` and `varMappings:` there yourself, and by the time anything
|
|
227
|
-
reads them the two are one merged map. See
|
|
228
|
-
[Managed config layers](repositories-file-formats.md#managed-config-layers).
|
|
300
|
+
`SOUS_DIR`, it does not decide which project is active, so it may be set in `.sous/.env.local` or
|
|
301
|
+
`.sous/.env` as well as in the shell.
|
|
229
302
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
one line each pointing at that README. None of the three is ever overwritten, so anything you
|
|
235
|
-
write in them stays. Directories that hold rendered output are deliberately left alone: what
|
|
236
|
-
lands there is yours.
|
|
303
|
+
The three files in the `500` to `599` band are written by sous, by key, so your comments and
|
|
304
|
+
formatting survive a write; you may edit them, and you may hand-write `repos:`, `subscriptions:`
|
|
305
|
+
and `varMappings:` in your primary config instead, which sous never touches. See
|
|
306
|
+
[Managed config layers](repositories-file-formats.md#managed-config-layers).
|
|
237
307
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
308
|
+
Every directory sous creates for its own bookkeeping explains itself: the first time it creates
|
|
309
|
+
one it writes a short `README.md` saying what the directory is, who writes to it, whether you may
|
|
310
|
+
edit it and whether it is committed, plus an `AGENTS.md` and a `CLAUDE.md` pointing at that
|
|
311
|
+
README. None is ever overwritten, and directories holding rendered output are left alone.
|
|
242
312
|
|
|
243
313
|
## Including recipe files in your own templates
|
|
244
314
|
|
|
245
|
-
A
|
|
246
|
-
|
|
247
|
-
```markdown
|
|
248
|
-
@~workflow/task-files/_partials/shared.md
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
The `~` is required. A bare `@path` in an include is always a relative path or a declared alias,
|
|
252
|
-
with no namespace fallback, so an include line can never quietly stop meaning a file on disk and
|
|
253
|
-
start meaning a recipe. Inside a recipe's own files, `~<namespace>` resolves against that
|
|
254
|
-
recipe's declared dependencies at their pinned versions; in your project's templates it resolves
|
|
255
|
-
against your project's subscriptions.
|
|
256
|
-
|
|
257
|
-
A `~namespace` reference addresses a recipe's own files and nothing else, so the path after the
|
|
258
|
-
recipe name may not contain `.` or `..` segments and may not be absolute. One that tries to leave
|
|
259
|
-
the recipe directory is refused with an error saying so, exactly as every other path sous reads
|
|
260
|
-
refuses `..`.
|
|
261
|
-
|
|
262
|
-
## Freshness, always-pull, and links
|
|
263
|
-
|
|
264
|
-
By default a build uses what the lockfile pins and does not talk to the network. Two things
|
|
265
|
-
change that.
|
|
266
|
-
|
|
267
|
-
**Always-pull** installs a newer in-range version whenever one exists, rather than holding the
|
|
268
|
-
locked one. It is set per repository or per subscription, or asked for once with
|
|
269
|
-
`sous subscription add --always-pull`. It never widens the range a subscription or a dependency
|
|
270
|
-
declared; it re-resolves within it. The lockfile is still regenerated every time, so it always
|
|
271
|
-
records what the last build actually used, and a project using always-pull simply accepts
|
|
272
|
-
routine lockfile diffs as the record of what changed.
|
|
273
|
-
|
|
274
|
-
**The freshness window** decides how often sous bothers to look upstream at all: five minutes by
|
|
275
|
-
default, configurable as `store.freshnessSeconds`, with `store.watchPollSeconds` doing the same
|
|
276
|
-
job for watch mode. A check that fails never breaks a build. The last good index stands, the
|
|
277
|
-
build says what happened, and it carries on.
|
|
278
|
-
|
|
279
|
-
A **linked** repository sits outside all of this. `sous repo link` points one repository's
|
|
280
|
-
resolution at a working copy on your machine, which is how a maintainer edits recipes; edits
|
|
281
|
-
happen in a checkout, never in the store. A link bypasses versions, the lockfile and freshness
|
|
282
|
-
checks, and those bypasses belong to one person's machine rather than to the team, so every
|
|
283
|
-
build announces a linked repository loudly:
|
|
315
|
+
A template may pull in a file from a recipe through the reserved `~` sigil, naming the recipe's
|
|
316
|
+
published identity and then the path inside it, on a line of its own:
|
|
284
317
|
|
|
285
318
|
```text
|
|
286
|
-
|
|
287
|
-
Their recipes are read from those checkouts, so versions, the lockfile and
|
|
288
|
-
freshness checks do not apply to them.
|
|
319
|
+
@~workflow/qa-helper/_partials/review-steps.md
|
|
289
320
|
```
|
|
290
321
|
|
|
322
|
+
The `~` is required. A bare `@path` is always a relative path or a declared alias, so an include
|
|
323
|
+
line can never quietly stop meaning a file on disk. Inside a recipe, `~<namespace>` resolves only
|
|
324
|
+
against that recipe's own `depends` and `subscribes` at the versions the lockfile pins, and the
|
|
325
|
+
path after the recipe name may not be absolute or hold a `.` or `..` segment.
|
|
326
|
+
|
|
291
327
|
## Where to go next
|
|
292
328
|
|
|
293
|
-
- [
|
|
294
|
-
|
|
295
|
-
- [Authoring a repository](repositories-authoring.md):
|
|
296
|
-
|
|
297
|
-
- [
|
|
298
|
-
|
|
299
|
-
- [Repository file formats](repositories-file-formats.md): every manifest, index and lockfile
|
|
300
|
-
schema
|
|
301
|
-
- [Skill categories](skill-categories.md): the canonical category list the official repository
|
|
302
|
-
uses as namespaces
|
|
329
|
+
- [Quickstart](repositories-quickstart.md): an empty project to a compiled skill, in order
|
|
330
|
+
- [Consuming recipes](repositories-consuming.md): adding, subscribing, building, removing
|
|
331
|
+
- [Authoring a repository](repositories-authoring.md): writing recipes, releasing, contributing
|
|
332
|
+
- [Recipe variables](repositories-variables.md): the resolution ladder and the question flow
|
|
333
|
+
- [Providers](repositories-providers.md): `github`, `gitlab` and `local`, and what each one can do
|
|
334
|
+
- [Repository file formats](repositories-file-formats.md): every manifest, index and schema
|
|
303
335
|
- [Command reference](commands.md): every command and flag
|
|
336
|
+
- [Troubleshooting](repositories-troubleshooting.md): what the errors mean and how to clear them
|
|
337
|
+
- [Skill categories](skill-categories.md): the category list the official repository uses
|
package/package.json
CHANGED