@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,303 @@
1
+ # Repositories
2
+
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
+ the way a package manager reads a registry: an index says what exists, a project says what it
6
+ wants, and a lockfile records exactly what it got.
7
+
8
+ This page explains the model and the guarantees. The task-oriented guides are
9
+ [Consuming recipes](repositories-consuming.md) and
10
+ [Authoring a repository](repositories-authoring.md), and every file schema lives in
11
+ [Repository file formats](repositories-file-formats.md).
12
+
13
+ ## Repositories, namespaces, recipes
14
+
15
+ Three nouns carry the whole system.
16
+
17
+ - A **repository** is the unit of trust and the unit of distribution. You add one to a project,
18
+ which is also how you trust it, and everything else flows from that.
19
+ - A **namespace** groups related recipes inside a repository. It is a plain name, it is not
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.
24
+
25
+ ```text
26
+ repository github.com/sous-io/sous-recipes
27
+ namespace workflow
28
+ recipe task-files 1.2.0
29
+ recipe github-projects 1.0.0
30
+ namespace communication
31
+ recipe control-flow 1.0.0
32
+ ```
33
+
34
+ A recipe is named by a **ref**: `workflow` for a whole namespace, `workflow/task-files` for one
35
+ recipe, `workflow/task-files@^1.2.0` to constrain the version, and
36
+ `sous-recipes:workflow/task-files` when two added repositories publish the same ref and sous
37
+ needs to be told which one you meant. Refs resolve across the cached indexes of every repository
38
+ the project has added; a genuine conflict is an error asking for the qualified form, never a
39
+ silent first match. The full grammar is in
40
+ [Refs: how anything is named](repositories-file-formats.md#refs-how-anything-is-named).
41
+
42
+ A ref of one word is a guess at a name, and sous works out what it meant: it looks for a
43
+ namespace with that name first, and for a recipe with that name second, across every repository
44
+ the project trusts. One match is used and reported by its full ref; several are a question. See
45
+ [Subscribe to a recipe](repositories-consuming.md#subscribe-to-a-recipe).
46
+
47
+ ## Trust
48
+
49
+ Adding a repository **is** trusting it. There is no separate trust command, no trusted-but-not-
50
+ added state, and no way to look inside a repository before deciding: until a repository is added,
51
+ sous downloads nothing from it, not even its index. That is deliberate. A trust decision made
52
+ by browsing content sous fetched from an untrusted source is not really a trust decision; the
53
+ decision rests on the URL and on who publishes it, and both of those are things you inspect
54
+ outside sous. Trusting a repository trusts every namespace and every recipe in it, including
55
+ recipes published later. Trusting alone executes nothing, but subscribing to something inside a
56
+ trusted repository can and probably will run scripts on your machine, so the trust question is
57
+ the last gate before that happens. Sous cannot tell you whether a repository deserves trust,
58
+ and it says so rather than implying otherwise.
59
+
60
+ `sous repo add` asks that question inline, with that wording. Resolution can also turn up a
61
+ repository a recipe depends on that your project has not added; those are asked about in one
62
+ consolidated question per round, each shown with its URL and the recipe that requires it. Any
63
+ refusal aborts the whole install, because sous installs a dependency closure whole or not at all.
64
+
65
+ ```term
66
+ $ sous repo add https://github.com/sous-io/sous-recipes
67
+ // sous prints the repository, its location and what trusting it means
68
+ Do you trust this repository? (y/N)
69
+ ```
70
+
71
+ Where there is no terminal to ask on, such as continuous integration, the run fails and names
72
+ both the repositories and the exact command that grants the trust. `--trust` acknowledges
73
+ without being asked, and is the flag a script uses; it is one spelling of the shared
74
+ confirmation flag, alongside `-y`, `--yes`, `-f` and `--force`:
75
+
76
+ ```bash
77
+ sous repo add https://github.com/sous-io/sous-recipes --trust
78
+ ```
79
+
80
+ Trust is project-level and lives in your project's config, so a colleague who clones the project
81
+ inherits it along with everything else. Trust plus the lockfile is the supply-chain defense:
82
+ nothing new enters a project except through an explicit, visible change to files under version
83
+ control.
84
+
85
+ !> Trust semantics do not soften for a repository that is already on your disk. A local path
86
+ added through the `local` provider goes through the same ceremony, because its recipes still run
87
+ on this machine.
88
+
89
+ ## The official repository, and `core`
90
+
91
+ Sous publishes one official repository, [`sous-io/sous-recipes`](https://github.com/sous-io/sous-recipes).
92
+ Its namespaces are drawn from the canonical [skill categories](skill-categories.md), plus one
93
+ extra namespace called `core`.
94
+
95
+ `core` is the exception to everything else on this page. It holds the skills that teach an agent
96
+ what sous is, why generated files must not be edited by hand, and where the source of a managed
97
+ file lives; without them an agent will cheerfully edit a compiled `CLAUDE.md` and wonder why the
98
+ change keeps disappearing. So `core` is auto-subscribed in every project, at the version that
99
+ matches the sous CLI you are running, and its source ships inside the sous package itself and
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.
103
+
104
+ Both wirings are ordinary config entries, and both can be switched off:
105
+
106
+ ```yaml
107
+ subscriptions:
108
+ core:
109
+ enabled: false
110
+ ```
111
+
112
+ Everything else in the official repository is opt-in, one `sous subscription add` at a time, and
113
+ `sous subscription remove core` records that opt-out for you.
114
+
115
+ ?> Namespace subscriptions are a first-class feature and are worth reaching for on other
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.
120
+
121
+ ## `depends` versus `subscribes`
122
+
123
+ A recipe manifest can declare two different relationships to other recipes, and the difference
124
+ is exactly one thing: whose files end up in your project.
125
+
126
+ | Relationship | Fetched and pinned | Trust-gated | Addressable from the declaring recipe | Files enter your project |
127
+ |--------------|--------------------|-------------|---------------------------------------|--------------------------|
128
+ | `depends` | yes | yes | yes | no |
129
+ | `subscribes` | yes | yes | yes | yes |
130
+
131
+ `depends` is a build dependency: shared partials, shared variable definitions, anything a recipe
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.
136
+
137
+ Both name their targets by LOCATION. A recipe in the same repository is a bare ref
138
+ (`workflow/sat`); a recipe in another repository is a locator URL whose scheme is the provider
139
+ (`github://sous-io/sous-recipes/workflow/sat@^1.1`), whose last two path segments are always the
140
+ namespace and the recipe. A project's own short name for a repository never appears in a
141
+ published manifest, because it is a label that project chose. The full grammar is in
142
+ [Repository file formats](repositories-file-formats.md#dependencies-named-by-location).
143
+
144
+ A release records what each version was published against, so installing a version installs the
145
+ versions it was released with rather than whatever its ranges reach today.
146
+
147
+ Both are declarative, and that is load-bearing rather than stylistic. Because the entire
148
+ dependency closure is readable from manifests alone, sous can show you every repository an
149
+ install would reach before it fetches any of them. Configuration that could subscribe by running
150
+ code would break that, which is why manifests are YAML or JSON and never JavaScript.
151
+
152
+ Removal is refcounted. Unsubscribing removes what that subscription alone brought in and leaves
153
+ anything another subscription or another recipe still holds, and says which of those holders
154
+ kept it.
155
+
156
+ ## The lockfile
157
+
158
+ `.sous/sous.lock.json` records the exact version and content hash of everything the project uses,
159
+ along with who holds each entry. It is committed. A fresh clone with no store on the machine
160
+ rebuilds precisely what the lockfile describes, fetching those versions and no others, and asking
161
+ nothing:
162
+
163
+ ```term
164
+ $ git clone git@github.com:my-team/my-project.git
165
+ >> 100%
166
+ $ sous build
167
+ Restoring recipes
168
+ This project's lockfile pins recipes that are not in the store on this machine,
169
+ so they are being fetched at exactly the versions it records.
170
+ restored: workflow/task-files
171
+ ```
172
+
173
+ Restore decides nothing. It never resolves a range, never picks a newer version, and never
174
+ prompts. Anything that would change what is installed changes the lockfile first, as a diff you
175
+ can read in review.
176
+
177
+ ## Providers
178
+
179
+ A provider is everything sous knows about one kind of repository host, and it is the only place
180
+ a host-specific fact is allowed to live. Sous ships three: `github`, `gitlab` and `local`.
181
+
182
+ A provider has two sides:
183
+
184
+ - **The read side**, which every provider answers: recognize a repository URL, take it apart into
185
+ host, owner and name, hand back the repository's `sous.index.json`, and fetch one recipe's
186
+ subtree at one tag. Nothing here clones a whole repository.
187
+ - **The write side**, which only a provider that can propose a change answers: report whether its
188
+ command line tool is installed and signed in, say whether you can push to the repository
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.
203
+
204
+ ## Where everything lives
205
+
206
+ | Location | Holds | Committed |
207
+ |----------|-------|-----------|
208
+ | `.sous/sous.lock.json` | the exact versions and hashes in use | yes |
209
+ | `.sous/conf.d/500-repos.jsonc` | the repositories the project trusts | yes |
210
+ | `.sous/conf.d/510-subscriptions.jsonc` | what the project subscribes to | yes |
211
+ | `.sous/conf.d/520-var-mappings.jsonc` | environment variable mapping records | yes |
212
+ | `.sous/sous.links.json` | this project's linked working copies | no |
213
+ | `.sous/repos/` | working copies cloned by `sous repo link` | no |
214
+ | `~/.sous/cache/` | the machine-wide recipe store | not in a project at all |
215
+ | `~/.sous/repos/` | working copies linked with `--global` | not in a project at all |
216
+ | `~/.sous/sous.links.json` | the machine-wide links map | not in a project at all |
217
+
218
+ The user-level directory is `~/.sous`, and `SOUS_HOME` moves it. Unlike `SOUS_CONFIG` and
219
+ `SOUS_DIR`, `SOUS_HOME` does not decide which project is active, so it may be set in
220
+ `.sous/.env.local` or `.sous/.env` as well as in the shell.
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).
229
+
230
+ Every directory sous creates for its own bookkeeping explains itself. The first time sous
231
+ creates one (`.sous/conf.d/`, `.sous/repos/`, `~/.sous` and everything under it), it writes a
232
+ short `README.md` there saying what the directory is, who writes to it, whether you may edit or
233
+ delete what is inside, and whether it is committed, plus an `AGENTS.md` and a `CLAUDE.md` holding
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.
237
+
238
+ The store is disposable by design. Every entry in it is re-fetchable from the pins in some
239
+ project's lockfile, so deleting `~/.sous/cache` costs a download and nothing else. `sous repo gc`
240
+ collects it back to a size cap, least recently used first, and never evicts an entry this
241
+ project's lockfile still pins.
242
+
243
+ ## Including recipe files in your own templates
244
+
245
+ A recipe's files are addressable from a template through the reserved `~` include sigil:
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:
284
+
285
+ ```text
286
+ One repository is LINKED to a working copy on this machine.
287
+ Their recipes are read from those checkouts, so versions, the lockfile and
288
+ freshness checks do not apply to them.
289
+ ```
290
+
291
+ ## Where to go next
292
+
293
+ - [Consuming recipes](repositories-consuming.md): adding, subscribing, building, and what lands
294
+ where
295
+ - [Authoring a repository](repositories-authoring.md): `sous repo init`, writing recipes,
296
+ releasing, and contributing
297
+ - [Recipe variables](repositories-variables.md): the resolution ladder, answers, and the
298
+ `sous vars` commands
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
303
+ - [Command reference](commands.md): every command and flag
@@ -0,0 +1,58 @@
1
+ # Skill Categories
2
+
3
+ Sous keeps one canonical list of skill categories. It is a small, closed vocabulary: it exists so
4
+ that a skill has an obvious home, so that two people filing similar skills reach for the same
5
+ word, and so that a reader scanning a repository can tell what is in it without opening
6
+ anything.
7
+
8
+ | Category | What belongs in it |
9
+ |----------|--------------------|
10
+ | `reasoning` | How an agent thinks through a problem: decomposition, self-checking, weighing evidence, knowing when it is stuck |
11
+ | `planning` | Turning an intent into an ordered plan, and keeping that plan current as the work moves |
12
+ | `architecture` | Designing systems and deciding structure: boundaries, dependencies, trade-offs, and how a decision gets recorded |
13
+ | `coding` | Writing and changing code: idioms, refactoring, language and framework practice |
14
+ | `data-manipulation` | Reading, transforming, querying and reshaping data, in files, databases or streams |
15
+ | `research` | Finding things out: searching a codebase, reading documentation, gathering evidence before acting |
16
+ | `tool-usage` | Driving a specific tool well: a CLI, a browser, an API, a service that has its own rules |
17
+ | `workflow` | The shape of the work itself: tickets, branches, task files, reviews, handoffs between sessions |
18
+ | `quality` | Confidence in what was built: tests, linting, review practice, and the standards being upheld |
19
+ | `communication` | How an agent talks: writing standards, interaction patterns, asking, reporting, disagreeing usefully |
20
+ | `operations` | Running things: builds, releases, deployment, environments, monitoring, recovery |
21
+ | `security` | Protecting the system and the people using it: secrets, permissions, supply chain, threat awareness |
22
+
23
+ ## Adding a category is a decision
24
+
25
+ The list above is the whole list. It is deliberately comprehensive rather than deliberately
26
+ small, so that in practice a new skill fits an existing category, and the answer to "which one?"
27
+ is a judgment call about the skill rather than an invitation to invent a thirteenth word.
28
+
29
+ Adding a category is a considered change to a shared vocabulary, never an ad hoc choice made
30
+ while filing one skill. A category that gets added because one skill did not obviously fit tends
31
+ to attract nothing else, and the list stops being useful the moment it stops being small. If a
32
+ skill genuinely resists every category above, that is worth discussing as a gap in the
33
+ vocabulary, on its own, before anything is filed.
34
+
35
+ ## Categories as namespaces
36
+
37
+ The official repository, [`sous-io/sous-recipes`](https://github.com/sous-io/sous-recipes), uses
38
+ this list directly: a namespace in that repository is a category from the table above, plus one
39
+ extra namespace, `core`, which holds the recipes that teach an agent about sous itself. `core` is
40
+ not a skill category. It is a distribution concern, and it exists because those recipes are
41
+ auto-subscribed in every project rather than chosen from a catalog.
42
+
43
+ Your own repository is under no obligation to use these names. Namespaces are just names, and a
44
+ team repository whose namespaces are its own product areas is a perfectly good repository. The
45
+ list is worth borrowing when what you publish is general-purpose skills that other people will
46
+ browse, because a shared vocabulary is what makes browsing work.
47
+
48
+ ?> A namespace subscription gets every recipe in the namespace, including recipes published
49
+ later, which is exactly what you want from a coherent category and exactly what you do not want
50
+ from a grab bag. That is the practical reason to keep a namespace meaning one thing. See
51
+ [Consuming recipes](repositories-consuming.md).
52
+
53
+ ## Where to go next
54
+
55
+ - [Repositories](repositories.md): the model, and how namespaces fit into it
56
+ - [Authoring a repository](repositories-authoring.md): declaring namespaces and filing recipes
57
+ under them
58
+ - [Design principles](design-principles.md): the constraints these choices answer to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sous-io/sous",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Compiles AI coding agent configuration (CLAUDE.md, skills, memories) from LiquidJS templates",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -27,52 +27,116 @@
27
27
  "access": "public"
28
28
  },
29
29
  "bin": {
30
- "xcv": "./bin/run.js"
30
+ "sous": "./bin/run.js"
31
31
  },
32
32
  "files": [
33
- "bin",
33
+ "bin/run.js",
34
34
  "src",
35
35
  "!src/**/*.spec.ts",
36
36
  "!src/test",
37
- "shared-prompts"
37
+ "recipes",
38
+ "docs/markdown/*.md",
39
+ "sous.config.schema.json"
38
40
  ],
39
41
  "scripts": {
40
42
  "build": "tsc",
41
- "sous:build": "./bin/xcv build --rebuild",
42
- "claude": "./bin/xcv launch claude",
43
+ "sous:build": "./bin/sous build --rebuild",
44
+ "claude": "./bin/sous launch claude",
43
45
  "clean": "rm -rf dist",
46
+ "schema:build": "tsx scripts/build-schema.mts",
47
+ "version:sync": "tsx scripts/sync-core-version.mts",
44
48
  "test": "vitest run",
45
49
  "test:watch": "vitest",
46
50
  "test:coverage": "vitest run --coverage",
47
51
  "test:e2e": "vitest run --config vitest.e2e.config.ts"
48
52
  },
49
53
  "dependencies": {
54
+ "@inquirer/core": "^11.1.7",
50
55
  "@inquirer/prompts": "^8.3.2",
51
56
  "@oclif/color": "^1.0.13",
52
57
  "@oclif/core": "^4",
53
58
  "chokidar": "^5.0.0",
54
59
  "glob": "^13.0.6",
60
+ "jsonc-parser": "^3.3.1",
55
61
  "liquidjs": "^10.25.0",
56
62
  "minimatch": "^10.2.4",
63
+ "semver": "^7.8.5",
57
64
  "tiktoken": "^1.0.22",
58
- "tsx": "^4"
65
+ "tsx": "^4",
66
+ "yaml": "^2.9.0",
67
+ "zod": "^4.4.3"
59
68
  },
60
69
  "devDependencies": {
61
70
  "@types/glob": "^8.1.0",
62
71
  "@types/node": "^22",
72
+ "@types/semver": "^7.8.0",
63
73
  "@vitest/coverage-v8": "^4.1.0",
64
74
  "memfs": "^4.56.11",
65
75
  "typescript": "^5",
66
76
  "vitest": "^4.1.0"
67
77
  },
68
78
  "oclif": {
69
- "bin": "xcv",
70
- "dirname": "xcv",
79
+ "bin": "sous",
80
+ "dirname": "sous",
71
81
  "flexibleTaxonomy": true,
72
82
  "topicSeparator": " ",
83
+ "additionalHelpFlags": [
84
+ "-h"
85
+ ],
73
86
  "commands": {
74
87
  "strategy": "pattern",
75
88
  "target": "./src/commands"
89
+ },
90
+ "topics": {
91
+ "config": {
92
+ "description": "Inspect the merged configuration"
93
+ },
94
+ "configs": {
95
+ "description": "Inspect the merged configuration",
96
+ "hidden": true
97
+ },
98
+ "repo": {
99
+ "description": "Manage the recipe repositories this project trusts"
100
+ },
101
+ "repos": {
102
+ "description": "Manage the recipe repositories this project trusts",
103
+ "hidden": true
104
+ },
105
+ "lock": {
106
+ "description": "Inspect and repair this project's lockfile"
107
+ },
108
+ "locks": {
109
+ "description": "Inspect and repair this project's lockfile",
110
+ "hidden": true
111
+ },
112
+ "namespace": {
113
+ "description": "Browse the namespaces the trusted repositories publish"
114
+ },
115
+ "namespaces": {
116
+ "description": "Browse the namespaces the trusted repositories publish",
117
+ "hidden": true
118
+ },
119
+ "recipe": {
120
+ "description": "Browse the recipes the trusted repositories publish"
121
+ },
122
+ "recipes": {
123
+ "description": "Browse the recipes the trusted repositories publish",
124
+ "hidden": true
125
+ },
126
+ "subscription": {
127
+ "description": "Manage which recipes this project subscribes to"
128
+ },
129
+ "subscriptions": {
130
+ "description": "Manage which recipes this project subscribes to",
131
+ "hidden": true
132
+ },
133
+ "vars": {
134
+ "description": "Recipe variables and their answers"
135
+ },
136
+ "var": {
137
+ "description": "Recipe variables and their answers",
138
+ "hidden": true
139
+ }
76
140
  }
77
141
  },
78
142
  "engines": {
@@ -10,12 +10,12 @@ user-invocable: false
10
10
  # About Agent Skills
11
11
 
12
12
  A skill is a directory containing a `SKILL.md` file and optional supporting files.
13
- Skills extend what a coding agent can do — invoke them directly with `/skill-name`,
13
+ Skills extend what a coding agent can do; invoke them directly with `/skill-name`,
14
14
  or they load automatically when the agent's decision logic matches the `description`.
15
15
 
16
16
  ## Where Skills Live
17
17
 
18
- Skills for this project live at `{{ skillsRoot }}`. Create and edit skills there —
18
+ Skills for this project live at `{{ skillsRoot }}`. Create and edit skills there,
19
19
  never in `.claude/skills/` or `.codex/skills/` directly. See `create-skill` for
20
20
  step-by-step instructions.
21
21
 
@@ -29,7 +29,7 @@ my-skill/
29
29
  └── scripts/ # Optional. Executable scripts.
30
30
  ```
31
31
 
32
- Supporting files must be referenced from `SKILL.md` — the agent will not know they
32
+ Supporting files must be referenced from `SKILL.md`; the agent will not know they
33
33
  exist otherwise. Keep `SKILL.md` under ~500 lines; move detailed reference material
34
34
  to `references/` files.
35
35
 
@@ -46,17 +46,17 @@ user-invocable: false
46
46
  ---
47
47
  ```
48
48
 
49
- **`name`** — becomes the `/slash-command`. Defaults to the directory name if omitted.
49
+ **`name`**: becomes the `/slash-command`. Defaults to the directory name if omitted.
50
50
 
51
- **`description`** — tells the agent when to invoke this skill. Use strong trigger
51
+ **`description`**: tells the agent when to invoke this skill. Use strong trigger
52
52
  language: open with "YOU MUST load this skill when...". Under 500 chars.
53
53
 
54
- **`disable-model-invocation`** — set `true` to prevent the agent from invoking the
54
+ **`disable-model-invocation`**: set `true` to prevent the agent from invoking the
55
55
  skill automatically. Use this for command skills that represent intentional,
56
56
  user-initiated actions (e.g. `/commit`, `/deploy`). If it makes sense for the agent
57
57
  to invoke the skill on the user's behalf, omit it.
58
58
 
59
- **`user-invocable`** — set `false` to hide the skill from the `/` menu. Use this on
59
+ **`user-invocable`**: set `false` to hide the skill from the `/` menu. Use this on
60
60
  all topic skills (`about-*`). They are reference material the agent loads
61
61
  automatically, not commands for the user to invoke.
62
62
 
@@ -69,14 +69,14 @@ shared scripts the action skills draw from. They are moderately descriptive and
69
69
  across many workflows. Always set `user-invocable: false`. Use the `about-*` prefix when
70
70
  the skill's primary purpose is background understanding.
71
71
 
72
- A topic skill's body holds fundamental knowledge — what is needed in ~75%+ of use cases.
72
+ A topic skill's body holds fundamental knowledge: what is needed in ~75%+ of use cases.
73
73
  Deeper reference material (complete tables, edge cases, advanced patterns) goes in
74
74
  `references/` files, loaded only when needed. When official documentation exists for the
75
75
  topic, fetch it once and store distilled versions in `references/`, including the official
76
76
  source URL so the agent can check anything not covered locally. This prevents repeated doc
77
77
  fetches during work sessions.
78
78
 
79
- **Action skills** perform a specific operation and are as thin as possible — they
79
+ **Action skills** perform a specific operation and are as thin as possible; they
80
80
  contain only what is exclusive to that action. All shared knowledge belongs in the
81
81
  parent topic skill. Action skills carry less cold-start context than topic skills: just
82
82
  enough to not be opaque, then delegate depth upward with `YOU MUST load`. Name action
@@ -85,7 +85,7 @@ specific type, include it after the verb (e.g. `create-skill` operates on a "ski
85
85
  The verb-first pattern immediately distinguishes action skills from topic skills in any
86
86
  skill listing.
87
87
 
88
- Non-command action skills must NOT have `disable-model-invocation: true` — that flag
88
+ Non-command action skills must NOT have `disable-model-invocation: true`; that flag
89
89
  removes the skill from the agent's context entirely, making it undiscoverable. A
90
90
  non-command action skill relies on its description to tell the agent when to invoke it
91
91
  automatically; omitting the flag is what makes that possible.
@@ -102,7 +102,7 @@ directory needs `.tpl.` naming or when writing LiquidJS syntax.
102
102
  ## General Principles
103
103
 
104
104
  **Knowledge lives at the highest common ancestor.** If two skills need the same
105
- knowledge, it belongs in the most general topic skill covering both — never
105
+ knowledge, it belongs in the most general topic skill covering both, never
106
106
  duplicated across skills. Before adding content anywhere, ask whether it belongs
107
107
  higher up.
108
108
 
@@ -117,7 +117,7 @@ directory). Teach the agent where to look rather than providing a snapshot that
117
117
  stale. Only document things stable by nature.
118
118
 
119
119
  **Use strong trigger language.** Descriptions must open with `YOU MUST load this
120
- skill when...`. Cross-references to other skills must use `YOU MUST load` — weak
120
+ skill when...`. Cross-references to other skills must use `YOU MUST load`; weak
121
121
  language like "consult" or "see" is not sufficient. In a skill body, write the
122
122
  requirement so it binds whichever agent executes ("The agent performing this work MUST
123
123
  load `x`"), not just the main session: delegated sub-agents start with fresh context and
@@ -135,8 +135,8 @@ that warrants its own skill.
135
135
 
136
136
  ## Template-Compiled Skills
137
137
 
138
- Every skill distributed from a shared library — whether this library (`sous`) or any other
139
- shared skill library — must use `SKILL.tpl.md`, not `SKILL.md`. This is required because
138
+ Every skill distributed from a shared library, whether this library (`sous`) or any other
139
+ shared skill library, must use `SKILL.tpl.md`, not `SKILL.md`. This is required because
140
140
  every distributed skill must end with a `## Source for this Skill` section (see below), and
141
141
  that section uses a template variable for the source path, which requires LiquidJS rendering.
142
142
  No exceptions.
@@ -159,15 +159,15 @@ compile time.
159
159
 
160
160
  ## Examples
161
161
 
162
- - [examples/about-something.md](examples/about-something.md) — a complete example of a topic (`about-*`) skill
163
- - [examples/do-something.md](examples/do-something.md) — a complete example of an action skill (command)
162
+ - [examples/about-something.md](examples/about-something.md): a complete example of a topic (`about-*`) skill
163
+ - [examples/do-something.md](examples/do-something.md): a complete example of an action skill (command)
164
164
 
165
165
  ## Reference Files
166
166
 
167
- - [frontmatter.md](references/frontmatter.md) — complete frontmatter field table and invocation matrix
168
- - [substitutions.md](references/substitutions.md) — `$ARGUMENTS`, `$ARGUMENTS[N]`, `$CLAUDE_SESSION_ID`, `$CLAUDE_SKILL_DIR`
169
- - [commands.md](references/commands.md) — command-specific conventions: descriptions, headings, arguments, `argument-hint`
170
- - [advanced-patterns.md](references/advanced-patterns.md) — dynamic context injection, subagent execution (`context: fork`), `allowed-tools`
167
+ - [frontmatter.md](references/frontmatter.md): complete frontmatter field table and invocation matrix
168
+ - [substitutions.md](references/substitutions.md): `$ARGUMENTS`, `$ARGUMENTS[N]`, `$CLAUDE_SESSION_ID`, `$CLAUDE_SKILL_DIR`
169
+ - [commands.md](references/commands.md): command-specific conventions: descriptions, headings, arguments, `argument-hint`
170
+ - [advanced-patterns.md](references/advanced-patterns.md): dynamic context injection, subagent execution (`context: fork`), `allowed-tools`
171
171
 
172
172
  ## Source for this Skill
173
173
 
@@ -25,9 +25,9 @@ has its own configuration file under `deploy/config/`.
25
25
 
26
26
  ## Reference Files
27
27
 
28
- - [references/environments.md](references/environments.md) — per-environment config
28
+ - [references/environments.md](references/environments.md): per-environment config
29
29
  options, required env vars, and access requirements
30
- - [references/rollback.md](references/rollback.md) — rollback procedures and known
30
+ - [references/rollback.md](references/rollback.md): rollback procedures and known
31
31
  failure modes
32
32
 
33
33
  # Other Skills
@@ -4,7 +4,7 @@
4
4
  ---
5
5
  name: deploy
6
6
  description: >
7
- YOU MUST use this skill when deploying the application. Do not use for rollbacks —
7
+ YOU MUST use this skill when deploying the application. Do not use for rollbacks;
8
8
  those follow a different process.
9
9
  disable-model-invocation: true
10
10
  ---