@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.
- package/README.md +121 -35
- package/bin/run.js +10 -1
- package/docs/markdown/README.md +27 -0
- package/docs/markdown/_sidebar.md +18 -0
- package/docs/markdown/commands.md +308 -0
- package/docs/markdown/config-discovery.md +74 -0
- package/docs/markdown/config-inspection.md +69 -0
- package/docs/markdown/config-layers.md +92 -0
- package/docs/markdown/config-variables.md +79 -0
- package/docs/markdown/configuration.md +71 -0
- package/docs/markdown/design-principles.md +59 -0
- package/docs/markdown/repositories-authoring.md +408 -0
- package/docs/markdown/repositories-consuming.md +580 -0
- package/docs/markdown/repositories-file-formats.md +1084 -0
- package/docs/markdown/repositories-variables.md +387 -0
- package/docs/markdown/repositories.md +303 -0
- package/docs/markdown/skill-categories.md +58 -0
- package/package.json +73 -9
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/SKILL.tpl.md +20 -20
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/about-something.md +2 -2
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/do-something.md +1 -1
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/advanced-patterns.md +6 -6
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/commands.md +5 -5
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/frontmatter.md +3 -3
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/SKILL.tpl.md +40 -25
- package/recipes/core/sous-skills/skills/about-sous/SKILL.tpl.md +70 -0
- package/recipes/core/sous-skills/skills/about-sous-configuration/SKILL.tpl.md +75 -0
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/create-skill/SKILL.tpl.md +8 -9
- package/recipes/core/sous-skills/sous.recipe.yaml +45 -0
- package/sous.config.schema.json +337 -0
- package/src/base-command.ts +220 -67
- package/src/commands/build.ts +150 -73
- package/src/commands/clear.ts +23 -15
- package/src/commands/compile.ts +74 -16
- package/src/commands/config/get.ts +110 -0
- package/src/commands/config/show.ts +32 -0
- package/src/commands/config/validate.ts +53 -0
- package/src/commands/help.ts +46 -0
- package/src/commands/launch.ts +36 -14
- package/src/commands/lock/rebuild.ts +241 -0
- package/src/commands/lock/show.ts +115 -0
- package/src/commands/namespace/list.ts +117 -0
- package/src/commands/namespace/show.ts +110 -0
- package/src/commands/prune.ts +3 -11
- package/src/commands/recipe/list.ts +95 -0
- package/src/commands/recipe/show.ts +301 -0
- package/src/commands/repo/add.ts +145 -0
- package/src/commands/repo/gc.ts +172 -0
- package/src/commands/repo/init.ts +136 -0
- package/src/commands/repo/link.ts +500 -0
- package/src/commands/repo/list.ts +179 -0
- package/src/commands/repo/release.ts +619 -0
- package/src/commands/repo/remove.ts +193 -0
- package/src/commands/repo/search.ts +189 -0
- package/src/commands/repo/submit.ts +133 -0
- package/src/commands/repo/unlink.ts +147 -0
- package/src/commands/subscription/add.ts +285 -0
- package/src/commands/subscription/list.ts +129 -0
- package/src/commands/subscription/remove.ts +181 -0
- package/src/commands/vars/ask.ts +374 -0
- package/src/commands/vars/index.ts +79 -0
- package/src/commands/vars/list.ts +67 -0
- package/src/commands/vars/show.ts +77 -0
- package/src/config-command.ts +30 -0
- package/src/lib/build-service.ts +206 -54
- package/src/lib/config-discovery.ts +220 -27
- package/src/lib/config-inspect.ts +145 -0
- package/src/lib/config-kernel.mjs +377 -0
- package/src/lib/config-schema.ts +361 -0
- package/src/lib/env-file.ts +328 -0
- package/src/lib/env-local.ts +18 -1
- package/src/lib/errors.ts +32 -0
- package/src/lib/include-resolver.ts +108 -15
- package/src/lib/interactive.ts +165 -0
- package/src/lib/markdown-compiler.ts +118 -37
- package/src/lib/package-info.ts +25 -0
- package/src/lib/pid-service.ts +32 -21
- package/src/lib/refs/find.ts +589 -0
- package/src/lib/refs/index.ts +12 -0
- package/src/lib/refs/pick.ts +147 -0
- package/src/lib/refs/scopes.ts +61 -0
- package/src/lib/repos/catalog-display.ts +116 -0
- package/src/lib/repos/catalog-inputs.ts +160 -0
- package/src/lib/repos/catalog.ts +722 -0
- package/src/lib/repos/core-recipe.ts +105 -0
- package/src/lib/repos/defaults.ts +175 -0
- package/src/lib/repos/formats/common.ts +389 -0
- package/src/lib/repos/formats/index-file.ts +215 -0
- package/src/lib/repos/formats/links-map.ts +96 -0
- package/src/lib/repos/formats/lockfile.ts +167 -0
- package/src/lib/repos/formats/patterns.ts +57 -0
- package/src/lib/repos/formats/recipe-manifest.ts +395 -0
- package/src/lib/repos/formats/repo-manifest.ts +88 -0
- package/src/lib/repos/formats/store-entry.ts +84 -0
- package/src/lib/repos/freshness.ts +208 -0
- package/src/lib/repos/git-clone.ts +312 -0
- package/src/lib/repos/identity.ts +89 -0
- package/src/lib/repos/index.ts +58 -0
- package/src/lib/repos/links.ts +353 -0
- package/src/lib/repos/load-manifest.ts +236 -0
- package/src/lib/repos/lock-service.ts +453 -0
- package/src/lib/repos/locked-namespace-resolver.ts +90 -0
- package/src/lib/repos/locked-recipes.ts +254 -0
- package/src/lib/repos/managed-layer.ts +422 -0
- package/src/lib/repos/namespace-resolver.ts +370 -0
- package/src/lib/repos/providers/base.ts +206 -0
- package/src/lib/repos/providers/git.ts +233 -0
- package/src/lib/repos/providers/github.ts +294 -0
- package/src/lib/repos/providers/gitlab.ts +263 -0
- package/src/lib/repos/providers/http.ts +102 -0
- package/src/lib/repos/providers/index-cache.ts +382 -0
- package/src/lib/repos/providers/index.ts +106 -0
- package/src/lib/repos/providers/local.ts +391 -0
- package/src/lib/repos/providers/provider.ts +401 -0
- package/src/lib/repos/recipe-config-layers.ts +287 -0
- package/src/lib/repos/recipe-targets.ts +223 -0
- package/src/lib/repos/ref-search.ts +46 -0
- package/src/lib/repos/ref.ts +513 -0
- package/src/lib/repos/reference-report.ts +122 -0
- package/src/lib/repos/release/bump.ts +161 -0
- package/src/lib/repos/release/git-state.ts +305 -0
- package/src/lib/repos/release/index-builder.ts +635 -0
- package/src/lib/repos/release/index.ts +16 -0
- package/src/lib/repos/release/plan.ts +512 -0
- package/src/lib/repos/release/submit-service.ts +496 -0
- package/src/lib/repos/release/tags.ts +243 -0
- package/src/lib/repos/release/validate.ts +463 -0
- package/src/lib/repos/resolver.ts +789 -0
- package/src/lib/repos/scaffold/index.ts +238 -0
- package/src/lib/repos/scaffold/templates.ts +413 -0
- package/src/lib/repos/seed.ts +414 -0
- package/src/lib/repos/store/contract.ts +64 -0
- package/src/lib/repos/store/hash.ts +114 -0
- package/src/lib/repos/store/recipe-store.ts +599 -0
- package/src/lib/repos/store/settings.ts +58 -0
- package/src/lib/repos/subscription-service.ts +2678 -0
- package/src/lib/repos/trust.ts +447 -0
- package/src/lib/settings.ts +546 -189
- package/src/lib/sous-home.ts +104 -0
- package/src/lib/state.ts +52 -20
- package/src/lib/vars/ask.ts +1152 -0
- package/src/lib/vars/definition-source.ts +252 -0
- package/src/lib/vars/display.ts +233 -0
- package/src/lib/vars/index.ts +18 -0
- package/src/lib/vars/ladder.ts +282 -0
- package/src/lib/vars/mappings.ts +265 -0
- package/src/lib/vars/names.ts +94 -0
- package/src/lib/vars/preanswers.ts +395 -0
- package/src/lib/vars/question-plan.ts +218 -0
- package/src/lib/vars/report.ts +228 -0
- package/src/lib/vars/safe-regex.ts +235 -0
- package/src/lib/vars/validate.ts +312 -0
- package/src/lib/watch-loop.ts +148 -0
- package/src/templating/init-liquid-engine.ts +58 -16
- package/src/utils/choice-prompt.ts +143 -0
- package/src/utils/command-errors.ts +186 -0
- package/src/utils/command-help.ts +45 -0
- package/src/utils/confirm-prompt.ts +110 -0
- package/src/utils/flags.ts +153 -0
- package/src/utils/formatting.ts +540 -55
- package/src/utils/prompts.ts +35 -1
- package/src/utils/sous-directory.ts +245 -0
- package/src/utils/table.ts +603 -0
- package/src/utils/value-prompt.ts +119 -0
- package/bin/xcv +0 -5
- package/shared-prompts/_partials/resume-task.md +0 -51
- package/shared-prompts/_partials/sub-agent-delegation.md +0 -32
- package/shared-prompts/_partials/update-task-file.md +0 -52
- package/shared-prompts/memories/automated-browser-tasks/INDEX.tpl.md +0 -52
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/SKILL.tpl.md +0 -102
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/auth-failure-handling.mjs +0 -81
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/chained-workflow.mjs +0 -126
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/simple-fetch.mjs +0 -92
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/architecture.md +0 -61
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/auth-and-sessions.md +0 -65
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/ctx-api.md +0 -96
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/installation.md +0 -104
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/script-conventions.md +0 -243
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/chrome-state.mjs +0 -148
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.mjs +0 -383
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.spec.mjs +0 -267
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/eslint.config.mjs +0 -56
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/harness.mjs +0 -169
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/keyring.mjs +0 -59
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/logger.mjs +0 -25
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/params.mjs +0 -140
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/run.mjs +0 -140
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/settings.tpl.mjs +0 -1
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/utils.mjs +0 -185
- package/shared-prompts/skills/automated-browser-tasks/create-automated-browser-task/SKILL.tpl.md +0 -52
- package/shared-prompts/skills/automated-browser-tasks/running-automated-browser-tasks/SKILL.tpl.md +0 -59
- package/shared-prompts/skills/automated-browser-tasks/update-automated-browser-task/SKILL.tpl.md +0 -47
- package/shared-prompts/skills/control-flow/approve/SKILL.tpl.md +0 -26
- package/shared-prompts/skills/control-flow/opine/SKILL.tpl.md +0 -58
- package/shared-prompts/skills/control-flow/repeat/SKILL.tpl.md +0 -27
- package/shared-prompts/skills/control-flow/research/SKILL.tpl.md +0 -34
- package/shared-prompts/skills/sous-skills/about-sous/SKILL.tpl.md +0 -51
- package/shared-prompts/skills/task-files/about-task-files/SKILL.tpl.md +0 -122
- package/shared-prompts/skills/task-files/continue-task-in-new-branch/SKILL.tpl.md +0 -80
- package/shared-prompts/skills/task-files/go/SKILL.tpl.md +0 -14
- package/shared-prompts/skills/task-files/resume-task/SKILL.tpl.md +0 -13
- package/shared-prompts/skills/task-files/start-task/SKILL.tpl.md +0 -93
- package/shared-prompts/skills/task-files/update/SKILL.tpl.md +0 -14
- package/shared-prompts/skills/task-files/update-task-file/SKILL.tpl.md +0 -13
- /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/substitutions.md +0 -0
- /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
|