@sous-io/sous 0.1.0 → 0.2.0

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.
Files changed (206) hide show
  1. package/README.md +121 -35
  2. package/bin/run.js +10 -1
  3. package/docs/markdown/README.md +27 -0
  4. package/docs/markdown/_sidebar.md +18 -0
  5. package/docs/markdown/commands.md +308 -0
  6. package/docs/markdown/config-discovery.md +74 -0
  7. package/docs/markdown/config-inspection.md +69 -0
  8. package/docs/markdown/config-layers.md +92 -0
  9. package/docs/markdown/config-variables.md +79 -0
  10. package/docs/markdown/configuration.md +71 -0
  11. package/docs/markdown/design-principles.md +59 -0
  12. package/docs/markdown/repositories-authoring.md +408 -0
  13. package/docs/markdown/repositories-consuming.md +580 -0
  14. package/docs/markdown/repositories-file-formats.md +1084 -0
  15. package/docs/markdown/repositories-variables.md +387 -0
  16. package/docs/markdown/repositories.md +303 -0
  17. package/docs/markdown/skill-categories.md +58 -0
  18. package/package.json +73 -9
  19. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/SKILL.tpl.md +20 -20
  20. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/about-something.md +2 -2
  21. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/do-something.md +1 -1
  22. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/advanced-patterns.md +6 -6
  23. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/commands.md +5 -5
  24. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/frontmatter.md +3 -3
  25. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/SKILL.tpl.md +40 -25
  26. package/recipes/core/sous-skills/skills/about-sous/SKILL.tpl.md +70 -0
  27. package/recipes/core/sous-skills/skills/about-sous-configuration/SKILL.tpl.md +75 -0
  28. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/create-skill/SKILL.tpl.md +8 -9
  29. package/recipes/core/sous-skills/sous.recipe.yaml +45 -0
  30. package/sous.config.schema.json +337 -0
  31. package/src/base-command.ts +220 -67
  32. package/src/commands/build.ts +150 -73
  33. package/src/commands/clear.ts +23 -15
  34. package/src/commands/compile.ts +74 -16
  35. package/src/commands/config/get.ts +110 -0
  36. package/src/commands/config/show.ts +32 -0
  37. package/src/commands/config/validate.ts +53 -0
  38. package/src/commands/help.ts +46 -0
  39. package/src/commands/launch.ts +36 -14
  40. package/src/commands/lock/rebuild.ts +241 -0
  41. package/src/commands/lock/show.ts +115 -0
  42. package/src/commands/namespace/list.ts +117 -0
  43. package/src/commands/namespace/show.ts +110 -0
  44. package/src/commands/prune.ts +3 -11
  45. package/src/commands/recipe/list.ts +95 -0
  46. package/src/commands/recipe/show.ts +301 -0
  47. package/src/commands/repo/add.ts +145 -0
  48. package/src/commands/repo/gc.ts +172 -0
  49. package/src/commands/repo/init.ts +136 -0
  50. package/src/commands/repo/link.ts +500 -0
  51. package/src/commands/repo/list.ts +179 -0
  52. package/src/commands/repo/release.ts +619 -0
  53. package/src/commands/repo/remove.ts +193 -0
  54. package/src/commands/repo/search.ts +189 -0
  55. package/src/commands/repo/submit.ts +133 -0
  56. package/src/commands/repo/unlink.ts +147 -0
  57. package/src/commands/subscription/add.ts +285 -0
  58. package/src/commands/subscription/list.ts +129 -0
  59. package/src/commands/subscription/remove.ts +181 -0
  60. package/src/commands/vars/ask.ts +374 -0
  61. package/src/commands/vars/index.ts +79 -0
  62. package/src/commands/vars/list.ts +67 -0
  63. package/src/commands/vars/show.ts +77 -0
  64. package/src/config-command.ts +30 -0
  65. package/src/lib/build-service.ts +206 -54
  66. package/src/lib/config-discovery.ts +220 -27
  67. package/src/lib/config-inspect.ts +145 -0
  68. package/src/lib/config-kernel.mjs +377 -0
  69. package/src/lib/config-schema.ts +361 -0
  70. package/src/lib/env-file.ts +328 -0
  71. package/src/lib/env-local.ts +18 -1
  72. package/src/lib/errors.ts +32 -0
  73. package/src/lib/include-resolver.ts +108 -15
  74. package/src/lib/interactive.ts +165 -0
  75. package/src/lib/markdown-compiler.ts +118 -37
  76. package/src/lib/package-info.ts +25 -0
  77. package/src/lib/pid-service.ts +32 -21
  78. package/src/lib/refs/find.ts +589 -0
  79. package/src/lib/refs/index.ts +12 -0
  80. package/src/lib/refs/pick.ts +147 -0
  81. package/src/lib/refs/scopes.ts +61 -0
  82. package/src/lib/repos/catalog-display.ts +116 -0
  83. package/src/lib/repos/catalog-inputs.ts +160 -0
  84. package/src/lib/repos/catalog.ts +722 -0
  85. package/src/lib/repos/core-recipe.ts +105 -0
  86. package/src/lib/repos/defaults.ts +175 -0
  87. package/src/lib/repos/formats/common.ts +389 -0
  88. package/src/lib/repos/formats/index-file.ts +215 -0
  89. package/src/lib/repos/formats/links-map.ts +96 -0
  90. package/src/lib/repos/formats/lockfile.ts +167 -0
  91. package/src/lib/repos/formats/patterns.ts +57 -0
  92. package/src/lib/repos/formats/recipe-manifest.ts +395 -0
  93. package/src/lib/repos/formats/repo-manifest.ts +88 -0
  94. package/src/lib/repos/formats/store-entry.ts +84 -0
  95. package/src/lib/repos/freshness.ts +208 -0
  96. package/src/lib/repos/git-clone.ts +312 -0
  97. package/src/lib/repos/identity.ts +89 -0
  98. package/src/lib/repos/index.ts +58 -0
  99. package/src/lib/repos/links.ts +353 -0
  100. package/src/lib/repos/load-manifest.ts +236 -0
  101. package/src/lib/repos/lock-service.ts +453 -0
  102. package/src/lib/repos/locked-namespace-resolver.ts +90 -0
  103. package/src/lib/repos/locked-recipes.ts +254 -0
  104. package/src/lib/repos/managed-layer.ts +422 -0
  105. package/src/lib/repos/namespace-resolver.ts +370 -0
  106. package/src/lib/repos/providers/base.ts +206 -0
  107. package/src/lib/repos/providers/git.ts +233 -0
  108. package/src/lib/repos/providers/github.ts +294 -0
  109. package/src/lib/repos/providers/gitlab.ts +263 -0
  110. package/src/lib/repos/providers/http.ts +102 -0
  111. package/src/lib/repos/providers/index-cache.ts +382 -0
  112. package/src/lib/repos/providers/index.ts +106 -0
  113. package/src/lib/repos/providers/local.ts +391 -0
  114. package/src/lib/repos/providers/provider.ts +401 -0
  115. package/src/lib/repos/recipe-config-layers.ts +287 -0
  116. package/src/lib/repos/recipe-targets.ts +223 -0
  117. package/src/lib/repos/ref-search.ts +46 -0
  118. package/src/lib/repos/ref.ts +513 -0
  119. package/src/lib/repos/reference-report.ts +122 -0
  120. package/src/lib/repos/release/bump.ts +161 -0
  121. package/src/lib/repos/release/git-state.ts +305 -0
  122. package/src/lib/repos/release/index-builder.ts +635 -0
  123. package/src/lib/repos/release/index.ts +16 -0
  124. package/src/lib/repos/release/plan.ts +512 -0
  125. package/src/lib/repos/release/submit-service.ts +496 -0
  126. package/src/lib/repos/release/tags.ts +243 -0
  127. package/src/lib/repos/release/validate.ts +463 -0
  128. package/src/lib/repos/resolver.ts +789 -0
  129. package/src/lib/repos/scaffold/index.ts +238 -0
  130. package/src/lib/repos/scaffold/templates.ts +413 -0
  131. package/src/lib/repos/seed.ts +414 -0
  132. package/src/lib/repos/store/contract.ts +64 -0
  133. package/src/lib/repos/store/hash.ts +114 -0
  134. package/src/lib/repos/store/recipe-store.ts +599 -0
  135. package/src/lib/repos/store/settings.ts +58 -0
  136. package/src/lib/repos/subscription-service.ts +2678 -0
  137. package/src/lib/repos/trust.ts +447 -0
  138. package/src/lib/settings.ts +546 -189
  139. package/src/lib/sous-home.ts +104 -0
  140. package/src/lib/state.ts +52 -20
  141. package/src/lib/vars/ask.ts +1152 -0
  142. package/src/lib/vars/definition-source.ts +252 -0
  143. package/src/lib/vars/display.ts +233 -0
  144. package/src/lib/vars/index.ts +18 -0
  145. package/src/lib/vars/ladder.ts +282 -0
  146. package/src/lib/vars/mappings.ts +265 -0
  147. package/src/lib/vars/names.ts +94 -0
  148. package/src/lib/vars/preanswers.ts +395 -0
  149. package/src/lib/vars/question-plan.ts +218 -0
  150. package/src/lib/vars/report.ts +228 -0
  151. package/src/lib/vars/safe-regex.ts +235 -0
  152. package/src/lib/vars/validate.ts +312 -0
  153. package/src/lib/watch-loop.ts +148 -0
  154. package/src/templating/init-liquid-engine.ts +58 -16
  155. package/src/utils/choice-prompt.ts +143 -0
  156. package/src/utils/command-errors.ts +186 -0
  157. package/src/utils/command-help.ts +45 -0
  158. package/src/utils/confirm-prompt.ts +110 -0
  159. package/src/utils/flags.ts +153 -0
  160. package/src/utils/formatting.ts +540 -55
  161. package/src/utils/prompts.ts +35 -1
  162. package/src/utils/sous-directory.ts +245 -0
  163. package/src/utils/table.ts +603 -0
  164. package/src/utils/value-prompt.ts +119 -0
  165. package/bin/xcv +0 -5
  166. package/shared-prompts/_partials/resume-task.md +0 -51
  167. package/shared-prompts/_partials/sub-agent-delegation.md +0 -32
  168. package/shared-prompts/_partials/update-task-file.md +0 -52
  169. package/shared-prompts/memories/automated-browser-tasks/INDEX.tpl.md +0 -52
  170. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/SKILL.tpl.md +0 -102
  171. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/auth-failure-handling.mjs +0 -81
  172. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/chained-workflow.mjs +0 -126
  173. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/simple-fetch.mjs +0 -92
  174. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/architecture.md +0 -61
  175. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/auth-and-sessions.md +0 -65
  176. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/ctx-api.md +0 -96
  177. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/installation.md +0 -104
  178. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/script-conventions.md +0 -243
  179. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/chrome-state.mjs +0 -148
  180. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.mjs +0 -383
  181. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.spec.mjs +0 -267
  182. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/eslint.config.mjs +0 -56
  183. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/harness.mjs +0 -169
  184. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/keyring.mjs +0 -59
  185. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/logger.mjs +0 -25
  186. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/params.mjs +0 -140
  187. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/run.mjs +0 -140
  188. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/settings.tpl.mjs +0 -1
  189. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/utils.mjs +0 -185
  190. package/shared-prompts/skills/automated-browser-tasks/create-automated-browser-task/SKILL.tpl.md +0 -52
  191. package/shared-prompts/skills/automated-browser-tasks/running-automated-browser-tasks/SKILL.tpl.md +0 -59
  192. package/shared-prompts/skills/automated-browser-tasks/update-automated-browser-task/SKILL.tpl.md +0 -47
  193. package/shared-prompts/skills/control-flow/approve/SKILL.tpl.md +0 -26
  194. package/shared-prompts/skills/control-flow/opine/SKILL.tpl.md +0 -58
  195. package/shared-prompts/skills/control-flow/repeat/SKILL.tpl.md +0 -27
  196. package/shared-prompts/skills/control-flow/research/SKILL.tpl.md +0 -34
  197. package/shared-prompts/skills/sous-skills/about-sous/SKILL.tpl.md +0 -51
  198. package/shared-prompts/skills/task-files/about-task-files/SKILL.tpl.md +0 -122
  199. package/shared-prompts/skills/task-files/continue-task-in-new-branch/SKILL.tpl.md +0 -80
  200. package/shared-prompts/skills/task-files/go/SKILL.tpl.md +0 -14
  201. package/shared-prompts/skills/task-files/resume-task/SKILL.tpl.md +0 -13
  202. package/shared-prompts/skills/task-files/start-task/SKILL.tpl.md +0 -93
  203. package/shared-prompts/skills/task-files/update/SKILL.tpl.md +0 -14
  204. package/shared-prompts/skills/task-files/update-task-file/SKILL.tpl.md +0 -13
  205. /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/substitutions.md +0 -0
  206. /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/references/liquid-filters.md +0 -0
@@ -0,0 +1,580 @@
1
+ # Consuming Recipes
2
+
3
+ This is the task-oriented guide to using someone else's recipes in your project. It assumes you
4
+ have read [Repositories](repositories.md) for the model, and it points at
5
+ [Repository file formats](repositories-file-formats.md) for every schema rather than repeating
6
+ them.
7
+
8
+ ## Add a repository
9
+
10
+ Adding a repository is how you trust it, so this is the one step that asks you a question:
11
+
12
+ ```term
13
+ $ sous repo add https://github.com/sous-io/sous-recipes
14
+ // the trust question, then one small download
15
+ Repository: sous-recipes
16
+ Location : https://github.com/sous-io/sous-recipes
17
+ Provider : github
18
+ Namespaces: communication, core, tool-usage, workflow
19
+ Recipes : 6
20
+
21
+ This project now trusts 'sous-recipes'. Nothing from it has been installed.
22
+ ```
23
+
24
+ Exactly one file is fetched: the repository's `sous.index.json`. That is everything sous needs
25
+ in order to resolve a ref, list versions and decide what to download later, so adding a
26
+ repository costs one small request and installs nothing.
27
+
28
+ | Flag | What it does |
29
+ |------|--------------|
30
+ | `--name <name>` | The short name refs will use. Defaults to the last segment of the URL |
31
+ | `--provider github\|gitlab\|local` | The provider that handles it, for a host the URL does not give away |
32
+ | `-y, --yes` | Accept trust without being asked, for a run with no terminal. `--trust`, `--force` and `-f` are the same flag |
33
+ | `--dry-run` | Print what would change without trusting or fetching anything |
34
+
35
+ The entry lands in `.sous/conf.d/500-repos.jsonc`, which is committed, so your colleagues inherit
36
+ both the repository and the trust decision. Sous edits that file by key, so anything you write in
37
+ it yourself, comments included, stays where you put it.
38
+
39
+ ## Browse what you trust
40
+
41
+ Four commands read the cached indexes and the lockfile, so all four work offline and none of them
42
+ downloads anything:
43
+
44
+ ```bash
45
+ sous namespace list
46
+ sous namespace show workflow
47
+ sous recipe list
48
+ sous recipe show workflow/task-files
49
+ ```
50
+
51
+ The listings answer "what is there, and what do I already have of it": every namespace with how
52
+ many recipes it holds and how much of it you subscribe to, and every recipe with its latest
53
+ version, the version your lockfile pins and whether you are subscribed.
54
+
55
+ `sous recipe show` is the one to read before subscribing to something. It describes one recipe
56
+ completely from what sous already has: every published version, what the version depends on (as the
57
+ recipe's manifest declares it, beside the exact version its repository's index resolved that to),
58
+ the questions it will ask you and where each answer is stored, and the directories its files would
59
+ be written into in this project.
60
+
61
+ ```term
62
+ $ sous recipe show workflow/task-files
63
+ Repository sous-recipes
64
+ Location https://github.com/sous-io/sous-recipes
65
+ Folder recipes/workflow/task-files
66
+ Latest version 1.0.1
67
+ Pinned version 1.0.1
68
+ Subscribed yes
69
+ ```
70
+
71
+ The questions and the file list live inside the recipe's own files, so a recipe you have not
72
+ installed is described from its index alone and says as much; subscribing to it fetches the rest.
73
+
74
+ ## Subscribe to a recipe
75
+
76
+ ```bash
77
+ sous subscription add workflow/task-files
78
+ ```
79
+
80
+ ?> `sous subscribe` is the original spelling of this command and still works, as does
81
+ `sous unsubscribe` for `subscription remove`. Every topic also answers to both spellings of its
82
+ name, so `sous subscriptions add`, `sous repos list` and `sous var show` all work too.
83
+
84
+ The ref names a namespace, one recipe, or either with a version range. The whole dependency
85
+ closure is resolved before anything is downloaded, and only then is anything written; installs
86
+ are whole or not at all.
87
+
88
+ | Flag | What it does |
89
+ |------|--------------|
90
+ | `-y, --yes` | Answer yes to both questions this command can ask: the subscribe confirmation, and the trust question for any repository it has to add. `--trust`, `--force` and `-f` are the same flag |
91
+ | `--accept-first` | When a one-word ref matches several things, take the first one listed |
92
+ | `--prerelease` | Let prerelease versions take part in version range matching |
93
+ | `--always-pull` | Install a newer in-range version whenever one exists, rather than holding the locked one |
94
+ | `--dry-run` | Print what would be installed without writing or downloading anything |
95
+ | `--no-build` | Change the subscription without rebuilding the project |
96
+
97
+ Subscribing changes what this project compiles, so the command finishes by building it: the same
98
+ compile and prune `sous build` runs, which means the new recipe's skills, memories and prompts are
99
+ already on disk when the command returns. `--no-build` records the subscription and leaves the
100
+ outputs alone, for when you would rather build later. If the build itself fails, the subscription
101
+ stays; it is already written and locked, and the message says so and names the command to run once
102
+ you have fixed the cause.
103
+
104
+ ### One-word refs
105
+
106
+ You do not have to remember which namespace a recipe lives in. A ref of one word is looked for
107
+ as a namespace first, and as a recipe name second, across the cached index of every repository
108
+ the project trusts:
109
+
110
+ ```term
111
+ $ sous subscription add task-files
112
+ Resolved to: sous-recipes:workflow/task-files
113
+ Recipe : task-files
114
+ Namespace : workflow
115
+ Repository : sous-recipes
116
+ Description: keeps one task file per branch
117
+
118
+ 'task-files' named one recipe, and nothing else, so that is what is being used.
119
+ ```
120
+
121
+ When the word means more than one thing, including the case where it is a namespace in one
122
+ repository and a recipe name in another, sous lists every candidate as a full ref and asks which
123
+ one you meant:
124
+
125
+ ```term
126
+ $ sous subscription add formatter
127
+ ? Which 'formatter' did you mean?
128
+ > my-recipes:formatter (the whole namespace 'formatter' in the repository 'my-recipes')
129
+ sous-recipes:tooling/formatter (the recipe 'formatter' in the namespace 'tooling' of the
130
+ repository 'sous-recipes': formats what a recipe writes)
131
+ ```
132
+
133
+ The order is stable and worth knowing, because `--accept-first` takes the first candidate without
134
+ asking: repositories come first in the order your config names them, with the built-in
135
+ `sous-recipes` ahead of them; then namespaces alphabetically; then, inside a namespace, the whole
136
+ namespace ahead of the recipes in it, which are alphabetical. A word that matches nothing is an
137
+ error naming every repository that was searched.
138
+
139
+ ### The confirmation
140
+
141
+ Subscribing changes your project, so sous says what it is about to do and asks before doing any
142
+ of it. Nothing is downloaded and nothing is written until the question is answered:
143
+
144
+ ```term
145
+ $ sous subscription add workflow/task-files
146
+
147
+ Subscribing to 'sous-recipes:workflow/task-files' installs the recipe 'task-files' from
148
+ the namespace 'workflow'.
149
+
150
+ Here is what that does:
151
+
152
+ • The files it ships are compiled into this project on the next build, which writes them
153
+ into this project's agent directories.
154
+ • Any scripts it ships can be run on this machine when an agent uses them. Sous does not
155
+ run them itself, and it cannot vouch for what they do.
156
+ • The variables it publishes are asked about at the end of this command, and the answers
157
+ are written into this project's env files.
158
+ • Its dependencies are fetched and pinned in this project's lockfile, at the exact
159
+ versions resolved now.
160
+ • If a dependency turns out to live in a repository this project does not trust, sous
161
+ stops and asks about that repository by name before fetching anything from it.
162
+
163
+ ? Proceed? (y/N)
164
+ ```
165
+
166
+ Answering no ends the command with nothing downloaded, no lockfile entry and no change to your
167
+ config. `--yes` accepts the plan without being asked, which is what a script or a Makefile wants;
168
+ `-y`, `--force`, `-f` and `--trust` are spellings of that same flag.
169
+ `--dry-run` states the plan and then reports what would be installed, asking nothing, because
170
+ there is nothing to decline.
171
+
172
+ Three files change: `.sous/conf.d/510-subscriptions.jsonc` records the subscription,
173
+ `.sous/sous.lock.json` records the exact versions and hashes, and the machine-wide store under
174
+ `~/.sous/cache` gains the recipe's files. All three, apart from the store, are committed.
175
+
176
+ If the closure reaches a repository you have not added, sous stops and asks about it by name,
177
+ showing which recipe requires it. Declining aborts the whole install:
178
+
179
+ ```term
180
+ $ sous subscription add workflow/needs-extras
181
+ // resolution reaches a repository this project has not added
182
+ One repository has to be trusted before this can continue.
183
+
184
+ extras
185
+ Location: https://github.com/some-team/extras
186
+ Required: tooling/formatter required by 'workflow/needs-extras'
187
+ ```
188
+
189
+ ?> A subscription entry holds the range; the ref you type may carry one (`@^1.2.0`), and the
190
+ range is what gets recorded. The subscription key itself is never qualified and never carries a
191
+ range. See [Project configuration](repositories-file-formats.md#project-configuration).
192
+
193
+ ## Build, and see what lands where
194
+
195
+ ```bash
196
+ sous build
197
+ ```
198
+
199
+ Nothing about a recipe's files is special once they are on disk: they compile exactly the way one
200
+ of your own `entryGlob` targets does, and the [`.tpl.` convention](configuration.md) applies
201
+ unchanged, so a `.tpl.md` file is rendered and loses `.tpl.` from its name while everything else
202
+ is copied verbatim.
203
+
204
+ Where each kind of content lands is your project's decision, under the `recipeOutputs` config
205
+ key:
206
+
207
+ ```js
208
+ recipeOutputs: {
209
+ skills: ["${projectRoot}/.claude/skills", "${projectRoot}/.codex/skills"],
210
+ memories: ["${projectRoot}/.claude/memories"],
211
+ prompts: ["${projectRoot}/prompts/recipes"],
212
+ },
213
+ ```
214
+
215
+ Only `skills` has a default, `<project root>/.claude/skills`, because that is where every agent
216
+ looks. Nothing else does. A content kind with no destination is skipped and the build says so
217
+ once, naming the key:
218
+
219
+ ```text
220
+ Some subscribed recipes contribute memories and prompts files, and this project has
221
+ nowhere to put them, so they were skipped.
222
+ Name a destination directory for each kind under the 'recipeOutputs' key of your
223
+ sous config, for example:
224
+ recipeOutputs: { memories: ["${projectRoot}/memories"], prompts: ["${projectRoot}/prompts"] }
225
+ ```
226
+
227
+ Recipe outputs are tracked like every other file sous writes, so `sous prune` removes what an
228
+ unsubscribed recipe used to write and `sous clear` removes all of it. Neither ever reaches into
229
+ a linked checkout or the machine-wide store.
230
+
231
+ ?> Only recipes held through `subscribes` contribute files. A recipe pulled in through `depends`
232
+ is fetched, pinned, and addressable from the recipe that declared it, and its files never enter
233
+ your output.
234
+
235
+ ## Recipes that configure your project
236
+
237
+ A recipe's `config` contents are not written anywhere. They are config layers, and they load
238
+ **after your primary config and before your own `conf.d/` drop-ins**:
239
+
240
+ ```text
241
+ primary config -> recipe config layers -> your conf.d/ layers -> managed 5xx layers
242
+ ```
243
+
244
+ So a recipe can supply defaults and your project always wins over them. Recipe layers are JSON
245
+ or YAML only; sous must be able to read everything a repository publishes without running any of
246
+ it, so an executable layer from a recipe is refused with a warning rather than loaded. Ordering
247
+ among recipe layers is by recipe key and then by path, which makes it the same on every machine.
248
+
249
+ A recipe layer may set only the keys that configure the recipe itself: `_vars`, `_aliases`,
250
+ `compilation`, `runtimeContext`, `recipeOutputs`, `store` and `varMappings`. Sous removes
251
+ anything else before merging and prints a warning naming the recipe and the key it removed.
252
+
253
+ !> Subscribing to a recipe is not a decision to let it decide what else you trust. A recipe
254
+ cannot add a repository to `repos:`, subscribe you to anything, point a `tools:` entry at a
255
+ program `sous launch` would run, map new environment variables in through `_env`, or rename your
256
+ project. Those decisions stay yours, and stay in your own config.
257
+
258
+ ## Answer the variables a recipe needs
259
+
260
+ A recipe publishes variable **definitions**; you supply **answers**. Subscribing asks whatever
261
+ is unanswered, reports whatever it inherited from an answer already in scope, and never re-asks
262
+ something that already fits:
263
+
264
+ ```text
265
+ Variables
266
+
267
+ Answers already in scope:
268
+ apiUrl : https://api.example.com from the shared scope name SOUS_VAR_API_URL, from
269
+ the .env file
270
+
271
+ Answers stored:
272
+ taskFileRoot: .sous/tasks SOUS_VAR_TASK_FILE_ROOT in .env
273
+ ```
274
+
275
+ In continuous integration there is no terminal, so an unanswered variable fails the run rather
276
+ than hanging on a prompt, and the failure names every environment variable that would satisfy it,
277
+ most specific first:
278
+
279
+ ```text
280
+ One variable still needs an answer, and there is no terminal to ask on.
281
+
282
+ Set one of the environment variables listed under each variable, or run
283
+ 'sous vars ask' from a terminal.
284
+
285
+ apiUrl (workflow/task-files): Where does the API live?
286
+ SOUS_VAR_WORKFLOW_TASK_FILES_API_URL (recipe scope)
287
+ SOUS_VAR_WORKFLOW_API_URL (namespace scope)
288
+ SOUS_VAR_API_URL (shared scope)
289
+ ```
290
+
291
+ Set any one of those names in the environment your pipeline runs in and the run proceeds.
292
+ [Recipe variables](repositories-variables.md) covers the ladder, the two env files, mapping
293
+ records and the `sous vars` commands in full.
294
+
295
+ ## Answering questions ahead of time
296
+
297
+ A script, a pipeline or a coding agent has no terminal and usually knows every answer already, so
298
+ it supplies them with the subscription rather than being asked for them. It takes two commands:
299
+ one to see the questions, one to answer them all.
300
+
301
+ First, ask what the subscription wants to know. A dry run installs nothing and writes nothing; it
302
+ prints the plan, and then every question the closure would ask, grouped by the recipe that
303
+ publishes it:
304
+
305
+ ```bash
306
+ sous subscription add workflow/task-files --dry-run --non-interactive
307
+ ```
308
+
309
+ ```text
310
+ Questions these recipes ask
311
+
312
+ These recipes ask 2 questions, 1 of which nothing answers yet.
313
+
314
+ workflow/task-files asks 2 questions:
315
+
316
+ taskFileRoot
317
+ about : The directory holding one task file per git branch.
318
+ example : .sous/tasks
319
+ stored-as : SOUS_VAR_TASK_FILE_ROOT
320
+ storage-path: /home/you/project/.sous/.env
321
+ answered : no, and this recipe requires an answer
322
+ answer-with : --answer taskFileRoot=<value>
323
+
324
+ apiUrl
325
+ about : The service every request this recipe generates is sent to.
326
+ example : https://api.example.com
327
+ stored-as : SOUS_VAR_API_URL
328
+ storage-path: /home/you/project/.sous/.env
329
+ answered : yes, from the shared scope name SOUS_VAR_API_URL, from the .env file
330
+ answer-with : --answer apiUrl=<value>
331
+ ```
332
+
333
+ Then do the whole thing in one command, with an answer for each question and `--yes` for the
334
+ confirmation:
335
+
336
+ ```bash
337
+ sous subscription add workflow/task-files --yes \
338
+ --answer taskFileRoot=.sous/tasks \
339
+ --answer apiUrl=https://api.example.com
340
+ ```
341
+
342
+ The rules are deliberately strict, because nobody reads a supplied answer before it is stored:
343
+
344
+ - Every answer is checked against its definition before anything is installed or written, so a run
345
+ either stores all of them or none of them. A value that does not fit fails the run naming the
346
+ constraint it violated and the publisher's example of a real answer.
347
+ - A name no recipe declares fails the run and lists every variable that is in play, grouped by
348
+ recipe, so a typo can never become a stored value under a name nothing reads.
349
+ - An answer for a variable that already has one replaces it, where that answer lives, and the
350
+ report says what it replaced.
351
+ - Anything left unanswered is asked for as usual, or, with no terminal, fails naming the
352
+ environment variables that would answer it.
353
+
354
+ The name is spelled exactly as the recipe declares it, in camelCase; the full
355
+ `namespace/recipe.name` key works too, which is what you use when two recipes publish the same
356
+ name. Everything after the first `=` is the answer, so a value may contain as many more as it
357
+ likes.
358
+
359
+ Answers can also come from a file, which suits a longer list or a value with spaces in it. It is
360
+ YAML or JSON (comments allowed), one entry per variable, and an `--answer` on the command line
361
+ wins over the same name in the file:
362
+
363
+ ```yaml
364
+ # answers.yaml
365
+ taskFileRoot: .sous/tasks
366
+ apiUrl: https://api.example.com
367
+ ```
368
+
369
+ ```bash
370
+ sous subscription add workflow/task-files --yes --answers-file ./answers.yaml
371
+ ```
372
+
373
+ ?> A dry run downloads nothing, so a recipe your machine does not hold yet has no manifest to
374
+ read and its questions cannot be listed. The run still succeeds and names the recipes it could
375
+ not describe; install them, or answer their questions when they are asked.
376
+
377
+ ## Look at what you have
378
+
379
+ ```bash
380
+ sous repo list
381
+ sous subscription list
382
+ sous search task
383
+ sous repo search browser --limit 50
384
+ ```
385
+
386
+ All three read only what is already on disk, so all three work offline and none of them downloads
387
+ anything. `repo list` shows each trusted repository with its location, provider, namespaces,
388
+ recipe count, and whether it is currently linked to a working copy. `subscription list` shows
389
+ every subscription the project declares, with the range it resolves within, the versions the
390
+ lockfile pins for it, where it came from, and whether it is on. `repo search`, which is also the
391
+ top-level `sous search`, matches text against recipe names, namespace names and descriptions
392
+ across every cached index. A repository whose index has never been fetched is reported as such
393
+ rather than silently left out; run `sous repo add` on it again to refresh the index.
394
+
395
+ `sous lock show` prints the other half of the picture: every recipe version your lockfile pins, the
396
+ repository it came from, and who holds it. When that file has drifted from your config, through a
397
+ hand edit or a bad merge, `sous lock rebuild` recomputes it from the subscriptions you declare and
398
+ drops whatever nothing holds any more; `--dry-run` shows the same summary and writes nothing.
399
+
400
+ ## When sous cannot ask
401
+
402
+ Every question in sous is gated by one rule. Sous treats a run as non-interactive, and so asks
403
+ nothing at all, when any of these is true:
404
+
405
+ - the `--non-interactive` flag is passed (every command that works on a project accepts it;
406
+ the three that run inside a recipe repository do not, because they have no `.sous/` to find
407
+ and take none of the project flags);
408
+ - the `CI` environment variable is set to anything other than `0`, `false`, `no` or `off`, which
409
+ is what every continuous integration runner does;
410
+ - stdin or stdout is not a terminal, which is what piping or scripting a command looks like.
411
+
412
+ A run like that fails rather than guessing, and the failure names the question that could not be
413
+ asked along with the flag that would have answered it ahead of time: `--yes` for the subscribe
414
+ confirmation and for the trust question (`-y`, `--force`, `-f` and `--trust` all mean the same
415
+ thing), `--accept-first` for the choice between candidate refs, and the exact environment
416
+ variables for a variable question. The command's own help is printed underneath the error, so
417
+ every other flag is in front of you, and `sous help <command>` prints the same screen on demand:
418
+
419
+ ```term
420
+ $ CI=true sous subscription add workflow/task-files
421
+ Sous has to ask whether to go ahead with subscribing to
422
+ 'sous-recipes:workflow/task-files', and it is not running where it can ask.
423
+ Why: the 'CI' environment variable is set to 'true'.
424
+ Answer it ahead of time: pass '--yes' (spelled '-y', '--force' or '--trust' if
425
+ you prefer) to accept the plan above without being asked.
426
+ ```
427
+
428
+ ?> The error and the help both go to stderr, so piping a command's output somewhere
429
+ (`sous config show | jq`) keeps working whether or not the run fails.
430
+
431
+ ## Remove a subscription
432
+
433
+ ```bash
434
+ sous subscription remove workflow/task-files
435
+ sous subscription remove workflow/task-files --dry-run
436
+ sous subscription remove workflow/task-files --no-build
437
+ ```
438
+
439
+ Removal is refcounted. Every lockfile entry records who holds it, so unsubscribing removes what
440
+ that subscription alone brought in and leaves anything another subscription or another recipe
441
+ still needs, reporting what stayed and why:
442
+
443
+ ```text
444
+ What stayed, and why
445
+
446
+ Recipe Still held by
447
+ tooling/formatter workflow/needs-extras
448
+ ```
449
+
450
+ The repositories those recipes came from stay trusted; withdrawing trust is a separate,
451
+ deliberate act.
452
+
453
+ Like adding one, removing a subscription finishes by building the project, so the files it used to
454
+ write are pruned before the command returns. `--no-build` leaves them where they are until the next
455
+ `sous build`. A build that fails does not put the subscription back; it is already gone from the
456
+ config and the lockfile, and the message says so.
457
+
458
+ ## Stop trusting a repository
459
+
460
+ ```bash
461
+ sous repo remove my-recipes
462
+ sous repo remove my-recipes --dry-run
463
+ sous repo remove my-recipes --yes
464
+ ```
465
+
466
+ Removing a repository withdraws the trust that adding it granted, and everything the project held
467
+ through it goes at the same time. Before anything is written the command says exactly what that
468
+ means here: the entry it takes out of the managed repositories layer, every subscription that
469
+ resolves into the repository, every locked recipe those subscriptions alone held, the output files
470
+ the next build prunes, and the checkout a link points at, if there is one. Then it asks once, and
471
+ `--yes` (also `-y`, `--force` and `-f`) answers ahead of time for a run with no terminal.
472
+
473
+ Each subscription is removed through the same refcounted path `sous subscription remove` uses, so a
474
+ recipe another subscription or another recipe still needs stays, and is reported with whoever is
475
+ holding it. A link to the repository is removed with it; the checkout itself stays on disk, because
476
+ it is a working copy sous did not necessarily put there. Like the subscription commands, this one
477
+ finishes by building the project, so the files those recipes wrote are pruned before it returns;
478
+ `--no-build` leaves them until the next `sous build`.
479
+
480
+ A subscription written in your own config file, rather than in the managed layer sous writes, is
481
+ named and left alone: sous never edits a config file you wrote.
482
+
483
+ Removing the built-in `sous-recipes` repository records `sous-recipes: { enabled: false }` in the
484
+ managed repositories layer instead of deleting an entry, for the same reason the `core` opt-out
485
+ below is recorded rather than deleted: the entry sous provides comes back on the next run.
486
+
487
+ ## Restore a fresh clone
488
+
489
+ A clone has the lockfile and the subscriptions, and no store. `sous build` restores exactly what
490
+ the lockfile pins, with no prompts and no version drift, then compiles:
491
+
492
+ ```term
493
+ $ git clone git@github.com:my-team/my-project.git
494
+ >> 100%
495
+ $ sous build
496
+ Restoring recipes
497
+ restored: workflow/task-files
498
+ compiled 12 targets
499
+ ```
500
+
501
+ If any variable the recipes need has no answer in the committed `.sous/.env` and none in the
502
+ environment, that is where the build stops, with the message shown above.
503
+
504
+ ## Collect the store
505
+
506
+ ```bash
507
+ sous repo gc
508
+ sous repo gc --dry-run
509
+ sous repo gc --max-bytes 268435456
510
+ ```
511
+
512
+ The store is machine-wide and disposable: everything in it is re-fetchable from the pins in a
513
+ lockfile. `repo gc` collects it back down to its size cap, evicting the least recently used
514
+ entries first, and protects everything this project's lockfile pins whatever that does to the
515
+ total. Entries other projects on the machine pin are re-fetchable too, so a pass may evict them;
516
+ the next build that needs one downloads it again.
517
+
518
+ The cap is `store.maxBytes` in your config, one gigabyte by default, and `--max-bytes` overrides
519
+ it for one run.
520
+
521
+ ## Opt out of `core`
522
+
523
+ The `core` namespace is auto-subscribed in every project, at the version matching the sous CLI
524
+ you are running, and seeded from inside the sous package so it works with no network. It carries
525
+ the skills that teach an agent what sous manages and why generated files must not be hand-edited,
526
+ which is why it arrives by default.
527
+
528
+ It is still an ordinary config entry, and one line removes it:
529
+
530
+ ```yaml
531
+ subscriptions:
532
+ core:
533
+ enabled: false
534
+ ```
535
+
536
+ `sous subscription remove core` writes exactly that line into the managed subscriptions layer for
537
+ you, because there is no entry to delete: the one sous provides comes back on the next run, so
538
+ only a recorded opt-out outlives it. `sous subscription add core` clears the opt-out again.
539
+ Either way the `sous-recipes` repository stays trusted and keeps appearing in `repo list` as
540
+ built in.
541
+
542
+ Disabling the built-in `sous-recipes` repository entry the same way switches off the auto-
543
+ subscription along with everything else that repository provides. Removing `core` means your
544
+ agents lose those instructions; if you remove it, make sure something else tells them not to edit
545
+ generated files.
546
+
547
+ ## Use a repository on this machine
548
+
549
+ A repository does not have to be hosted. Give `sous repo add` a path, relative or absolute, or
550
+ the same path in `file:///` form, and sous reads it through the built-in `local` provider:
551
+
552
+ ```bash
553
+ sous repo add /home/me/Projects/my-recipes --name my-recipes --trust
554
+ sous repo add ../my-recipes --name my-recipes --trust
555
+ ```
556
+
557
+ A relative path is resolved against the working directory before anything else happens, and the
558
+ absolute form is what lands in the config; a repository on this machine is machine-specific
559
+ either way.
560
+
561
+ It is meant for local development and for tests: authoring a repository, trying a recipe before
562
+ publishing it, or running a whole workflow with no network at all. The index is read from the
563
+ working tree when the file is there, so an index you are still writing is picked up without a
564
+ commit. A recipe's files come from the version's tag in the local git repository; a directory
565
+ that is not a git repository has no versions to honor, so its working tree is copied instead.
566
+
567
+ !> A local path is trusted through the same ceremony as a hosted repository. Its recipes still
568
+ run on this machine, and "it is already on my disk" is not a reason to skip the question.
569
+
570
+ For editing a repository you are already subscribed to, reach for
571
+ [`sous repo link`](repositories-authoring.md#edit-a-repository-in-place) instead; it redirects
572
+ one repository's resolution at a working copy without changing what your project subscribes to.
573
+
574
+ ## Where to go next
575
+
576
+ - [Recipe variables](repositories-variables.md): answers, the resolution ladder, `sous vars`
577
+ - [Authoring a repository](repositories-authoring.md): publishing recipes of your own
578
+ - [Repository file formats](repositories-file-formats.md): every schema, including
579
+ [`recipeOutputs`](repositories-file-formats.md#recipeoutputs-where-the-files-land)
580
+ - [Command reference](commands.md): every command and flag