@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
package/README.md CHANGED
@@ -1,9 +1,20 @@
1
+ <p align="center">
2
+ <a href="https://sous.io">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/sous-io/sous/main/docs/img/logo-on-dark-sm.png">
5
+ <img src="https://raw.githubusercontent.com/sous-io/sous/main/docs/img/logo-on-white-sm.png" alt="Sous" height="180">
6
+ </picture>
7
+ </a>
8
+ </p>
9
+
1
10
  # sous
2
11
 
3
12
  sous compiles AI coding agent configuration from templates. You write skills, memories, and
4
13
  instructions once as LiquidJS templates in layered sources, then sous renders them into the
5
14
  formats agents actually read: `.claude/` plus `CLAUDE.md` for Claude Code, `.codex/` plus
6
- `AGENTS.md` for Codex. The CLI binary is named `xcv`.
15
+ `AGENTS.md` for Codex. The CLI binary is named `sous`.
16
+
17
+ **New to sous? Watch the animated introduction at [sous.io](https://sous.io).**
7
18
 
8
19
  ## Why
9
20
 
@@ -17,6 +28,12 @@ formats agents actually read: `.claude/` plus `CLAUDE.md` for Claude Code, `.cod
17
28
 
18
29
  Install the CLI:
19
30
 
31
+ ```bash
32
+ npm install -g @sous-io/sous
33
+ ```
34
+
35
+ Or run it from a clone (useful when developing sous itself):
36
+
20
37
  ```bash
21
38
  git clone git@github.com:sous-io/sous.git
22
39
  cd sous
@@ -25,7 +42,7 @@ npm link
25
42
  ```
26
43
 
27
44
  Then set up a project. A project needs a `.sous/` directory holding a config file, named
28
- `sous.config.js`, `sous.config.mjs`, or `sous.config.json`:
45
+ `sous.config.js`, `sous.config.mjs`, `sous.config.json`, or `sous.config.yaml`:
29
46
 
30
47
  ```bash
31
48
  cd /path/to/your/project
@@ -37,32 +54,28 @@ A config that compiles one file:
37
54
 
38
55
  ```js
39
56
  export const config = {
40
- projects: {
41
- myproject: {
42
- name: "My Project",
43
- _vars: { projectRoot: "${sousDir}/.." },
44
- compilation: {
45
- targets: [
46
- {
47
- entryPoint: "${sousDir}/AGENTS.md",
48
- outputs: [{ destinationFile: "${projectRoot}/CLAUDE.md" }],
49
- },
50
- ],
57
+ name: "My Project",
58
+ _vars: { projectRoot: "${sousDir}/.." },
59
+ compilation: {
60
+ targets: [
61
+ {
62
+ entryPoint: "${sousDir}/AGENTS.md",
63
+ outputs: [{ destinationFile: "${projectRoot}/CLAUDE.md" }],
51
64
  },
52
- },
65
+ ],
53
66
  },
54
67
  };
55
68
  ```
56
69
 
57
70
  `${sousDir}` is the `.sous/` directory sous found, so a config can name paths relative to
58
- itself without hardcoding anything machine-specific. With a single project defined you do
59
- not need `defaultProject`; sous uses the only one. Then build:
71
+ itself without hardcoding anything machine-specific. One config describes one project. Then
72
+ build:
60
73
 
61
74
  ```bash
62
- xcv build
75
+ sous build
63
76
  ```
64
77
 
65
- `xcv build` compiles every configured target and prunes outputs that are no longer in the
78
+ `sous build` compiles every configured target and prunes outputs that are no longer in the
66
79
  config. Config discovery walks up from the current directory until it finds a `.sous/`
67
80
  directory holding a config, so you can run it from anywhere inside the project. Pass
68
81
  `--config <path>` to point at one explicitly instead.
@@ -75,19 +88,22 @@ anything resolves. There are two layers:
75
88
  - `.sous/.env.local` is gitignored. Put machine-specific values and secrets here.
76
89
 
77
90
  Precedence, highest first: your shell environment, then `.env.local`, then `.env`. So
78
- `FOO=bar xcv build` beats both files, and `.env.local` beats `.env` per key. This repo
91
+ `FOO=bar sous build` beats both files, and `.env.local` beats `.env` per key. This repo
79
92
  ships `.sous/.env.local.example` documenting the layer.
80
93
 
81
94
  Useful commands:
82
95
 
83
96
  | Command | What it does |
84
97
  |---|---|
85
- | `xcv build` | Compile, then prune stale outputs |
86
- | `xcv build --watch` | Rebuild on source changes |
87
- | `xcv compile` | Compile only |
88
- | `xcv prune` | Remove outputs no longer in the config |
89
- | `xcv clear` | Delete every file sous wrote for the project |
90
- | `xcv launch claude` | Build, then start the agent |
98
+ | `sous build` | Compile, then prune stale outputs |
99
+ | `sous build --watch` | Rebuild on source changes |
100
+ | `sous compile` | Compile only |
101
+ | `sous prune` | Remove outputs no longer in the config |
102
+ | `sous clear` | Delete every file sous wrote for the project |
103
+ | `sous launch claude` | Build, then start the agent |
104
+ | `sous config show` | Print the merged config (all layers) as JSON |
105
+ | `sous config get <path>` | Read one value by dot-path; `--layers` shows which file set it |
106
+ | `sous config validate` | Validate the merged config: schema, then variable resolution |
91
107
 
92
108
  ## How it works
93
109
 
@@ -113,28 +129,98 @@ each level can define variables:
113
129
  }
114
130
  ```
115
131
 
116
- Variables resolve later-wins across scopes: auto-injected, env, root, project, compilation,
132
+ Variables resolve later-wins across scopes: auto-injected, env, config, compilation,
117
133
  target, output. Templates read them as `{{ varName }}`; config files reference them as `${varName}`.
118
134
  The auto-injected ones include `${sousDir}` and `${sousConfigPath}` for the discovered
119
135
  config, and `${sousTemplatePath}` for the template being rendered.
120
136
 
121
137
  Sources come in three tiers, each able to build on the one above it:
122
138
 
123
- 1. **Built-in** shared prompts that ship with sous, covering skill authoring, templating, and
124
- the sous conventions themselves.
125
- 2. **Team-shared**, a repo your team owns, holding the configs everyone should get.
139
+ 1. **Published recipes**, fetched from a recipe repository and pinned in your project's
140
+ lockfile. The official repository publishes the `core` namespace, which teaches an agent
141
+ about sous itself and which every project gets without asking, plus recipes for skill
142
+ authoring, task tracking and more.
143
+ 2. **Team-shared**, a recipe repository your team owns, holding the recipes everyone should
144
+ get.
126
145
  3. **Per-project**, the project's own `.sous/` directory, for anything specific to it.
127
146
 
128
- The built-in tier is reachable without knowing where sous is installed. `@include` paths
129
- accept aliases, and two are always defined: `~sous-shared` for the shared prompts that ship
130
- with sous, and `~project` for the project root. So `@~sous-shared/_partials/sub-agent-delegation.md`
131
- composes a built-in block into your own instruction file, and an `entryGlob` can point at a
132
- built-in skill bundle to compile it into your project. Define your own aliases with an
133
- `_aliases` block to do the same for a team-shared repo.
147
+ A recipe's files are reachable without knowing where anything is installed. An `@include`
148
+ path may name a recipe by its namespace, so
149
+ `@~workflow/task-files/_partials/resume-task.md` composes a block published by the recipe
150
+ `workflow/task-files`, at the version your project has pinned, into your own instruction
151
+ file. `@~project/...` names your project's root, and you can define your own aliases with
152
+ an `_aliases` block.
134
153
 
135
154
  Sous records every file and directory it writes in a state file, `.sous/sous.state.json` by
136
155
  default, which is what lets `prune` and `clear` clean up precisely instead of guessing.
137
156
 
157
+ ## Composing config from layers
158
+
159
+ One config can grow large, so sous lets you split it. Alongside the primary
160
+ `sous.config.*`, any file matching `.sous/conf.d/*.{js,mjs,json,yaml}` is a layer. Sous loads
161
+ the primary first, then the `conf.d/` files sorted bytewise-lexicographically (identical order
162
+ on every machine), and merges them into one config: objects deep-merge key by key, scalars are
163
+ later-wins, and arrays concatenate in load order. Every layer is forced back to plain JSON
164
+ before merging, so functions, `RegExp`, `Date`, and `undefined` do not survive a layer.
165
+
166
+ ```
167
+ .sous/
168
+ sous.config.js # base config
169
+ conf.d/
170
+ 100-tools.json # adds or overrides tools
171
+ 200-skills.yaml # adds compilation targets
172
+ ```
173
+
174
+ For anything JSON cannot express, a `.js`/`.mjs` layer may export a `configure` function
175
+ instead of (or alongside) a `config` object. Sous calls it with the cumulative config so far
176
+ and a small builder, and merges the result:
177
+
178
+ ```js
179
+ export function configure(currentConfig, builder) {
180
+ // currentConfig is the live merged config; mutate it by reference, or return
181
+ // an object to merge. builder.env(name, fallback), builder.loadConfig(path),
182
+ // builder.loadConfigs(glob), and builder.merge(obj) are available.
183
+ currentConfig._vars.apiBase = builder.env("API_BASE", "https://example.com");
184
+ }
185
+ ```
186
+
187
+ `configure` may be async. Builder paths (`loadConfig`/`loadConfigs`) run before variable
188
+ resolution, so they accept only the auto-vars `${sousDir}`, `${sousConfDir}`, `${sousRootPath}`,
189
+ and `${sousVersion}`; any other `${var}` in a builder path is an error.
190
+
191
+ ## Locating the config
192
+
193
+ By default sous walks up from the current directory to find the `.sous/` holding a config.
194
+ You can point it elsewhere with an environment variable or a flag; every command accepts these:
195
+
196
+ | Flag | Env var | What it overrides |
197
+ |---|---|---|
198
+ | `--config` / `-c` / `--sous-config` | `SOUS_CONFIG` | The exact primary config file |
199
+ | `--sous-dir` | `SOUS_DIR` | The `.sous/` directory to use |
200
+ | `--sous-confd` | `SOUS_CONFD` | The `conf.d/` directory (defaults to `<sousDir>/conf.d`) |
201
+
202
+ Precedence, highest first: flag, then env var, then walk-up discovery. These location inputs
203
+ are read from the real environment only, never from `.env` or `.env.local` (those files are
204
+ found by discovery, so they cannot decide where discovery looks).
205
+
206
+ ## Validating and inspecting config
207
+
208
+ `sous config validate` runs the full pipeline: it merges every layer, checks it against the
209
+ schema, then resolves variables, reporting the first failure with a readable message.
210
+ `sous config show` prints the merged config as JSON, and `sous config get <dot.path>` reads a
211
+ single value; add `--layers` to see which layer file set it and to what.
212
+
213
+ Config is validated against a JSON Schema on every load. A config may declare a `version`
214
+ field; omit it or set it to `1`. JSON layers can point an editor at the shipped schema with a
215
+ `"$schema"` key for autocompletion and inline validation:
216
+
217
+ ```json
218
+ {
219
+ "$schema": "./sous.config.schema.json",
220
+ "version": 1
221
+ }
222
+ ```
223
+
138
224
  ## Platform support
139
225
 
140
226
  - **Ubuntu** is where sous is developed and tested.
package/bin/run.js CHANGED
@@ -14,4 +14,13 @@ const { execute, settings } = await import("@oclif/core");
14
14
  // the (unshipped) typescript devDependency is missing.
15
15
  settings.enableAutoTranspile = false;
16
16
 
17
- await execute({ development: true, dir: import.meta.url });
17
+ // oclif's development mode turns on its debug setting, which makes every error
18
+ // it prints a raw stack trace. Sous reports its own errors as sentences (see
19
+ // src/utils/command-errors.ts), so development mode is switched on only when
20
+ // SOUS_DEBUG asks for the traces; anything that gets past a command's own
21
+ // reporting then prints its stack too.
22
+ const debugRequested = !["", "0", "false", "no", "off"].includes(
23
+ (process.env.SOUS_DEBUG ?? "").trim().toLowerCase()
24
+ );
25
+
26
+ await execute({ development: debugRequested, dir: import.meta.url });
@@ -0,0 +1,27 @@
1
+ # Sous Documentation
2
+
3
+ Sous is an agent configuration manager for LLM coding tools: it compiles markdown templates,
4
+ aggregates configuration from many sources, and keeps the files your coding agents rely on
5
+ current. The CLI is called `sous` and ships on npm as
6
+ [`@sous-io/sous`](https://www.npmjs.com/package/@sous-io/sous). Earlier releases installed the
7
+ same CLI under the name `xcv`; every command below is unchanged apart from that name.
8
+
9
+ ```term
10
+ $ npm install -g @sous-io/sous
11
+ >> 100%
12
+ $ sous build
13
+ building "My Project"...
14
+ compiled 4 targets, pruned 1 stale file
15
+ ```
16
+
17
+ ?> These docs are young. **Configuration** and **Repositories** are the reference material so
18
+ far; more will follow.
19
+
20
+ ## Where to look
21
+
22
+ - Watch the [animated introduction](../) for the full pitch
23
+ - Learn [how sous is configured](configuration.md)
24
+ - Share configuration between projects with [repositories](repositories.md)
25
+ - Look up a command in the [command reference](commands.md)
26
+ - Read the [design principles](design-principles.md) that constrain every feature
27
+ - Read the [source on GitHub](https://github.com/sous-io/sous)
@@ -0,0 +1,18 @@
1
+ - [Overview](/)
2
+ - [Design principles](design-principles.md)
3
+ - [Skill categories](skill-categories.md)
4
+ - [Command reference](commands.md)
5
+ - **Configuration**
6
+ - [The config file](configuration.md)
7
+ - [Discovery and overrides](config-discovery.md)
8
+ - [Layers and merging](config-layers.md)
9
+ - [Variables](config-variables.md)
10
+ - [Inspecting and validating](config-inspection.md)
11
+ - **Repositories**
12
+ - [Overview](repositories.md)
13
+ - [Consuming recipes](repositories-consuming.md)
14
+ - [Recipe variables](repositories-variables.md)
15
+ - [Authoring a repository](repositories-authoring.md)
16
+ - [File formats](repositories-file-formats.md)
17
+ - **ADRs**
18
+ - [0001: Repositories](adrs/0001-repositories.md)
@@ -0,0 +1,308 @@
1
+ # Command Reference
2
+
3
+ Every command the `sous` CLI ships, with its arguments and its own flags. Run any of them with
4
+ `--help` for the same information in your terminal.
5
+
6
+ ## The flags every project command shares
7
+
8
+ These four locate the configuration and are accepted by every command that works on a project.
9
+ They are listed once here rather than repeated in every table below.
10
+
11
+ | Flag | What it does |
12
+ |------|--------------|
13
+ | `-c, --config <path>` | Path to a sous config file, or to a directory holding one. Overrides `.sous/` discovery |
14
+ | `--sous-config <path>` | Alias of `--config` |
15
+ | `--sous-dir <path>` | Path to the `.sous` directory to use, overriding walk-up discovery |
16
+ | `--sous-confd <path>` | Path to the `conf.d/` drop-in layer directory, overriding `<sousDir>/conf.d` |
17
+
18
+ The environment variables `SOUS_CONFIG`, `SOUS_DIR` and `SOUS_CONFD` do the same jobs; a flag
19
+ beats the matching variable, and both beat walk-up discovery.
20
+ [Discovery and overrides](config-discovery.md) covers the precedence in full. One more variable,
21
+ `SOUS_DEBUG`, is read by every command: it turns stack traces back on when something fails
22
+ (see [Exit behavior](#exit-behavior)).
23
+
24
+ ?> Three commands take none of these, because they run inside a recipe repository rather than
25
+ inside a project: `sous repo init`, `sous repo release` and `sous repo submit`. A recipe
26
+ repository has no `.sous/` directory to discover. All three do take `--non-interactive`:
27
+ `repo init` and `repo submit` accept it without ever having a question to suppress, and
28
+ `repo release` reads the flag, the terminal and the `CI` environment variable to decide whether
29
+ it may ask, with `--ci` or `--yes` settling it outright.
30
+
31
+ ## Flags common to many commands
32
+
33
+ A few flags mean the same thing wherever they appear, so the tables below name them without
34
+ explaining them again.
35
+
36
+ | Flag | What it does |
37
+ |------|--------------|
38
+ | `-y, --yes` | Answers yes to every confirmation the command would ask. `--force` and `-f` are the same flag; so is `--trust` on the commands that trust a repository |
39
+ | `--non-interactive` | The opposite instruction: never ask anything. A run that would have prompted fails instead, naming the question and the flag that would have answered it |
40
+ | `--dry-run` | Prints what the command would do and writes, downloads and asks nothing |
41
+ | `-h, --help` | Prints the command's own help and exits |
42
+
43
+ `sous clear` is the one command whose primary spelling is `--force` rather than `--yes`, because
44
+ that is the spelling it has always had; `-y` and `--yes` are aliases of it there and behave
45
+ identically. `sous repo init --force` is a different flag with a different meaning (overwrite an
46
+ existing repository), and it is not a confirmation.
47
+
48
+ Help is available in four forms, all of which draw the same screen:
49
+
50
+ ```bash
51
+ sous --help
52
+ sous repo add --help
53
+ sous repo add -h
54
+ sous help repo add
55
+ ```
56
+
57
+ `sous help` on its own lists the topics and commands, and `sous help <topic>` lists one topic's
58
+ commands.
59
+
60
+ ## Singular and plural
61
+
62
+ Every topic answers to both spellings of its name, so nothing hinges on remembering which one
63
+ sous prefers: `repo` and `repos`, `subscription` and `subscriptions`, `namespace` and
64
+ `namespaces`, `recipe` and `recipes`, `lock` and `locks`, `var` and `vars`, `config`
65
+ and `configs`. The tables below print the spelling `sous --help` shows; the other one runs
66
+ exactly the same command.
67
+
68
+ ## Building
69
+
70
+ | Command | Arguments | Own flags |
71
+ |---------|-----------|-----------|
72
+ | `sous build` | none | `--no-prune`, `--no-compile`, `--rebuild`, `--dry-run`, `--strict`, `-w, --watch` |
73
+ | `sous compile` | none | `--strict`, `--rebuild`, `--dry-run`, `-w, --watch` |
74
+ | `sous prune` | none | `--dry-run` |
75
+ | `sous clear` | none | `-f, --force` (also `-y, --yes`) |
76
+ | `sous launch` | `TOOL...` | `--no-build`, `--continuous` |
77
+
78
+ `build` is compile plus prune, and is the command you want almost always. `--rebuild` ignores
79
+ cached hashes and reprocesses every output; `--strict` fails on the first compilation error
80
+ rather than reporting and continuing; `--watch` rebuilds on every change to a source file, a
81
+ config layer, or a linked recipe checkout.
82
+
83
+ `clear` deletes every file and directory sous has written for the project, and asks first unless
84
+ you pass `--force` (or `-y`, or `--yes`). Neither `prune` nor `clear` ever reaches into a linked checkout or the
85
+ machine-wide recipe store.
86
+
87
+ `launch` builds and then spawns a coding agent configured under `tools` in your config. Any
88
+ argument it does not recognize is forwarded to the tool. A flag that collides with one of sous's
89
+ own goes after a bare `--`, which forwards everything following it verbatim:
90
+
91
+ ```bash
92
+ sous launch claude --resume
93
+ sous launch claude -- -c
94
+ ```
95
+
96
+ ## Inspecting the configuration
97
+
98
+ | Command | Arguments | Own flags |
99
+ |---------|-----------|-----------|
100
+ | `sous config show` | none | none |
101
+ | `sous config get` | `PATH` | `--layers` |
102
+ | `sous config validate` | none | none |
103
+
104
+ `show` and `get` write machine-readable output to standard output, with the decorative header and
105
+ any error block routed to standard error, so `sous config show | jq` works even when the config is
106
+ broken. `PATH` is a dot-path with `[n]` for array indices, such as
107
+ `compilation.targets[0].entryPoint`, and `--layers` prints one `old -> new` line per config layer
108
+ that changed the value. `validate` runs the resolvers that schema validation alone cannot,
109
+ surfacing reference cycles and undefined `${var}` references.
110
+
111
+ See [Inspecting and validating](config-inspection.md).
112
+
113
+ ## Repositories
114
+
115
+ | Command | Arguments | Own flags |
116
+ |---------|-----------|-----------|
117
+ | `sous repo add` | `URL` | `--name <name>`, `--provider github\|gitlab\|local`, `-y, --yes` (also `--trust`), `--dry-run` |
118
+ | `sous repo remove` | `REPO` | `-y, --yes` (also `-f, --force`), `--dry-run`, `--no-build` |
119
+ | `sous repo list` | none | `--verbose` |
120
+ | `sous repo search` | `TEXT` | `--limit <n>` (default 25) |
121
+ | `sous repo gc` | none | `--max-bytes <n>`, `--dry-run` |
122
+ | `sous repo link` | `REPO` (a short name, a URL or a path) `[PATH]` | `--global`, `-y, --yes` (also `--trust`), `--dry-run` |
123
+ | `sous repo unlink` | `REPO` | `--global`, `--dry-run` |
124
+
125
+ `repo add` is the trust ceremony; it asks inline, and the confirmation flag is how a run with no
126
+ terminal acknowledges instead. `--trust` is the spelling the ceremony reads best with, and it is
127
+ the same flag as `-y`, `--yes`, `-f` and `--force`. `URL` may be an address or an absolute path to a repository on this
128
+ machine. `list` and `search` read only what is already cached, so both work offline and neither
129
+ downloads anything.
130
+
131
+ `repo remove` is the reverse of `repo add`: it stops trusting a repository. Before it writes
132
+ anything it prints what goes with it, so the decision is made on facts: the entry itself, every
133
+ subscription that resolves into the repository, every locked recipe those subscriptions alone held,
134
+ the output files the next build prunes, and the linked checkout, if one points at it. Then it asks
135
+ once, and the confirmation flag answers ahead of time. The link entry is removed with the
136
+ repository; the checkout itself stays on disk. The command finishes by building the project, the
137
+ same way the subscription commands do, so the files those recipes wrote are gone when it returns;
138
+ `--no-build` leaves the outputs alone. Removing the built-in `sous-recipes` repository records
139
+ `sous-recipes: { enabled: false }` in the managed repositories layer rather than deleting an entry,
140
+ because the entry sous provides comes back on every run.
141
+
142
+ `repo search` is also a top-level `sous search`, because searching is how you find something to
143
+ subscribe to before you know what any of it is called.
144
+
145
+ ## Browsing what a project trusts
146
+
147
+ | Command | Arguments | Own flags |
148
+ |---------|-----------|-----------|
149
+ | `sous namespace list` | none | none |
150
+ | `sous namespace show` | `REF` (a namespace, optionally `repo:namespace`) | none |
151
+ | `sous recipe list` | none | none |
152
+ | `sous recipe show` | `REF` (a recipe, a recipe name on its own, or either with a `repo:` qualifier) | none |
153
+
154
+ All four read the cached repository indexes and the lockfile, so they work offline and download
155
+ nothing. A trusted repository whose index has never been fetched is named at the end of a listing
156
+ rather than left out of it.
157
+
158
+ `namespace list` shows every namespace, how many recipes it holds, and how much of it this project
159
+ subscribes to: the whole namespace, some recipes, or none. `namespace show` adds every recipe in
160
+ one namespace, with the latest published version, the version this project pins, and whether it is
161
+ subscribed.
162
+
163
+ `recipe list` shows the same per-recipe columns across every namespace. `recipe show` describes one
164
+ recipe completely: the repository and its location, every published version labeled as the latest
165
+ one, the pinned one or an earlier one, what the version depends on (both as the recipe's manifest
166
+ declares it and as its repository's index resolved it at release time), the questions it asks with
167
+ the environment variable each answer is stored under, and the directories its files are written
168
+ into. The questions and the file list come from the recipe's own manifest, so a recipe this machine
169
+ does not hold yet is described from its index alone and says so.
170
+
171
+ ## The lockfile
172
+
173
+ | Command | Arguments | Own flags |
174
+ |---------|-----------|-----------|
175
+ | `sous lock show` | none | none |
176
+ | `sous lock rebuild` | none | `--dry-run` |
177
+
178
+ `lock show` prints what `.sous/sous.lock.json` pins: the recipe, the version, the repository it came
179
+ from, and who holds it (this project, or the recipes that require it).
180
+
181
+ `lock rebuild` recomputes the whole file from the subscriptions the config declares and the cached
182
+ indexes, then writes it. It starts from an empty lockfile, so an entry nothing holds any more is
183
+ dropped rather than carried through; that makes it the repair for a file that has drifted from the
184
+ config through a hand edit or a bad merge. It asks nothing and grants no trust: a subscription whose
185
+ closure reaches a repository this project has not added fails, naming the repository. It downloads
186
+ nothing, so a recipe whose files are not on this machine has its own dependencies left out, and is
187
+ named when that happens. `--dry-run` prints the same summary and writes nothing.
188
+
189
+ ## Subscriptions
190
+
191
+ | Command | Arguments | Own flags |
192
+ |---------|-----------|-----------|
193
+ | `sous subscription list` | none | none |
194
+ | `sous subscription add` | `REF` | `--prerelease`, `--always-pull`, `-y, --yes` (also `--trust`), `--accept-first`, `--answer <name>=<value>`, `--answers-file <path>`, `--dry-run`, `--no-build` |
195
+ | `sous subscription remove` | `REF` | `--dry-run`, `--no-build` |
196
+
197
+ `sous subscribe` and `sous unsubscribe` are the original spellings of `subscription add` and
198
+ `subscription remove`, and both still work.
199
+
200
+ Adding or removing a subscription changes what the project compiles, so both commands finish by
201
+ building it: the same compile and prune `sous build` runs, so a newly subscribed recipe's files
202
+ are on disk when the command returns and a removed one's files are gone. `--no-build` changes the
203
+ subscription and leaves the outputs alone. A build that fails leaves the subscription change in
204
+ place, since it is already written and locked, and says so.
205
+
206
+ `REF` is a ref: `namespace`, `namespace/recipe`, either with an `@<range>`, and optionally
207
+ qualified with `repo:`. See
208
+ [Refs: how anything is named](repositories-file-formats.md#refs-how-anything-is-named).
209
+
210
+ `subscription add --dry-run` installs nothing and, after the plan, prints every question the
211
+ recipes would ask: what each variable is for, where its answer would be stored, and whether
212
+ anything answers it already. `--answer <name>=<value>`, repeated, answers those questions ahead of
213
+ time, and `--answers-file <path>` reads the same pairs from a YAML or JSON file; together they are
214
+ how a run with no terminal subscribes to a recipe that asks questions. See
215
+ [Answering questions ahead of time](repositories-consuming.md#answering-questions-ahead-of-time).
216
+
217
+ `subscription list` reads the config and the lockfile only, so it works offline. It reports every
218
+ subscription the project declares, switched-off ones included, with the range it resolves within,
219
+ the versions the lockfile pins for it, where it came from, and whether it is on.
220
+
221
+ Removing the `core` subscription sous provides itself records `core: { enabled: false }` in the
222
+ managed subscriptions layer rather than deleting an entry, because the default would otherwise
223
+ come back on the next run. Adding it back clears the opt-out. Either way the `sous-recipes`
224
+ repository stays trusted and keeps appearing in `repo list` as built in.
225
+
226
+ `repo link` is written three ways. `REPO` on its own, as the short name of a repository this
227
+ project has already added, clones it into `.sous/repos/<owner>/<name>`, or into
228
+ `$SOUS_HOME/repos/<owner>/<name>` with `--global`. `REPO` followed by a `PATH` links the checkout
229
+ at that path to that repository and clones nothing. A path in the `REPO` slot, on its own, links
230
+ the checkout already at that path where it is, under the short name its repo manifest suggests.
231
+ Naming a repository this project has not added, by URL or by path, runs the same trust ceremony
232
+ `repo add` runs, since a linked repository's recipes are read with no version, lockfile or hash
233
+ check; it asks inline, and `--trust` (or any other spelling of the confirmation flag)
234
+ acknowledges instead for a run with no terminal.
235
+
236
+ ## Authoring a repository
237
+
238
+ These three run inside a recipe repository and take none of the config-locating flags.
239
+
240
+ | Command | Arguments | Own flags |
241
+ |---------|-----------|-----------|
242
+ | `sous repo init` | `[DIRECTORY]` | `--name <name>`, `--namespace <name>`, `--force`, `--dry-run` |
243
+ | `sous repo release` | none | `--namespace <ns>`, `--recipe <ns/name>`, `--bump patch\|minor\|major\|prerelease`, `--no-bump`, `--include-unchanged`, `--tag`, `--push`, `--yes`, `--check`, `--ci`, `--dry-run` |
244
+ | `sous repo submit` | none | `--title <text>`, `--body <text>`, `--draft`, `--dry-run` |
245
+
246
+ `sous repo release` plans first, asks once, and then bumps, regenerates the index, commits and
247
+ tags in one run. `--namespace` and `--recipe` are repeatable and narrow the run; `--check` reads
248
+ only and cannot be combined with `--bump`, `--tag` or `--push`; `--ci` is the merge preset and
249
+ implies `--no-bump`. See [Authoring a repository](repositories-authoring.md).
250
+
251
+ ## Variables
252
+
253
+ | Command | Arguments | Own flags |
254
+ |---------|-----------|-----------|
255
+ | `sous vars list` | none | `--file <path>` |
256
+ | `sous vars show` | `NAME` | `--file <path>` |
257
+ | `sous vars ask` | `[NAME]` | `--repo <name>`, `--namespace <name>`, `--var <name>`, `--accept-first`, `--all`, `--file <path>`, `--answer <name>=<value>`, `--answers-file <path>`, `--dry-run` |
258
+
259
+ `vars list` prints every variable in play, with the environment variable that answered each one
260
+ and where the value came from. `vars show` prints one variable in full, including every
261
+ environment variable on the resolution ladder and which rung answered. `NAME` is a bare variable
262
+ name or a full `namespace/recipe.name` key.
263
+
264
+ On `vars ask`, `NAME` is a reference like any other: a variable, an environment variable that
265
+ answers one, a recipe, a namespace or a repository, at any level of qualification, and anything
266
+ larger than a variable asks every question it publishes. `--repo`, `--namespace` and `--var`
267
+ (repeatable) narrow the same way, and `--accept-first` takes the first candidate when the name
268
+ means more than one thing. `--file` reads definitions from a standalone
269
+ definitions file instead of the project's subscribed recipes. `--answer` and `--answers-file`
270
+ answer questions ahead of time, exactly as they do on `subscription add`.
271
+
272
+ Bare `sous vars` is shorthand for `vars list`, and `sous vars <name>` for `vars show <name>`. A
273
+ variable whose name is also a subcommand name (`list`, `show` or `ask`) has to be reached the
274
+ long way, as `sous vars show list`.
275
+
276
+ See [Recipe variables](repositories-variables.md).
277
+
278
+ ## Tables and terminal width
279
+
280
+ Every listing sous prints fits itself to the terminal it is running in. Columns shrink toward
281
+ their minimums, a long description wraps onto more lines, and a path or a URL is cut in the
282
+ middle so the host and the last segment both survive. On a terminal too narrow to hold
283
+ everything, the columns that matter least step aside, and one line under the table names them:
284
+ `Hidden at this width: URL. Widen the terminal to see it.` Nothing is hidden when the output is
285
+ not a terminal (a pipe, a file, a CI log), which is laid out at a fixed width instead, so a
286
+ recorded run always shows every column.
287
+
288
+ `sous repo list --verbose` adds the namespaces each repository publishes, on a dim line under
289
+ that repository's row.
290
+
291
+ ## Exit behavior
292
+
293
+ Every command exits non-zero on a configuration problem and prints a plain-language error block
294
+ naming the file at fault. There is no warn-and-continue: a broken config halts sous rather than
295
+ producing output built on a guess.
296
+
297
+ What a failure prints is the message and nothing else. Forget an argument, misspell a flag, or
298
+ pass a value a flag does not accept, and sous prints the sentence describing the mistake and
299
+ then that command's own help, so the flag you wanted is on the screen already. No expected
300
+ failure prints a stack trace.
301
+
302
+ Set the `SOUS_DEBUG` environment variable to anything but `0`, `false`, `no` or `off` and every
303
+ failure prints its stack trace to standard error underneath the message. It is there for
304
+ debugging sous itself; nothing else changes when it is set.
305
+
306
+ ```bash
307
+ SOUS_DEBUG=1 sous build
308
+ ```