@sous-io/sous 0.1.1 → 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 (205) hide show
  1. package/README.md +115 -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 +72 -8
  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/shared-prompts/_partials/resume-task.md +0 -51
  166. package/shared-prompts/_partials/sub-agent-delegation.md +0 -32
  167. package/shared-prompts/_partials/update-task-file.md +0 -52
  168. package/shared-prompts/memories/automated-browser-tasks/INDEX.tpl.md +0 -52
  169. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/SKILL.tpl.md +0 -102
  170. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/auth-failure-handling.mjs +0 -81
  171. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/chained-workflow.mjs +0 -126
  172. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/simple-fetch.mjs +0 -92
  173. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/architecture.md +0 -61
  174. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/auth-and-sessions.md +0 -65
  175. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/ctx-api.md +0 -96
  176. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/installation.md +0 -104
  177. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/script-conventions.md +0 -243
  178. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/chrome-state.mjs +0 -148
  179. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.mjs +0 -383
  180. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.spec.mjs +0 -267
  181. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/eslint.config.mjs +0 -56
  182. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/harness.mjs +0 -169
  183. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/keyring.mjs +0 -59
  184. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/logger.mjs +0 -25
  185. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/params.mjs +0 -140
  186. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/run.mjs +0 -140
  187. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/settings.tpl.mjs +0 -1
  188. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/utils.mjs +0 -185
  189. package/shared-prompts/skills/automated-browser-tasks/create-automated-browser-task/SKILL.tpl.md +0 -52
  190. package/shared-prompts/skills/automated-browser-tasks/running-automated-browser-tasks/SKILL.tpl.md +0 -59
  191. package/shared-prompts/skills/automated-browser-tasks/update-automated-browser-task/SKILL.tpl.md +0 -47
  192. package/shared-prompts/skills/control-flow/approve/SKILL.tpl.md +0 -26
  193. package/shared-prompts/skills/control-flow/opine/SKILL.tpl.md +0 -58
  194. package/shared-prompts/skills/control-flow/repeat/SKILL.tpl.md +0 -27
  195. package/shared-prompts/skills/control-flow/research/SKILL.tpl.md +0 -34
  196. package/shared-prompts/skills/sous-skills/about-sous/SKILL.tpl.md +0 -51
  197. package/shared-prompts/skills/task-files/about-task-files/SKILL.tpl.md +0 -122
  198. package/shared-prompts/skills/task-files/continue-task-in-new-branch/SKILL.tpl.md +0 -80
  199. package/shared-prompts/skills/task-files/go/SKILL.tpl.md +0 -14
  200. package/shared-prompts/skills/task-files/resume-task/SKILL.tpl.md +0 -13
  201. package/shared-prompts/skills/task-files/start-task/SKILL.tpl.md +0 -93
  202. package/shared-prompts/skills/task-files/update/SKILL.tpl.md +0 -14
  203. package/shared-prompts/skills/task-files/update-task-file/SKILL.tpl.md +0 -13
  204. /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/substitutions.md +0 -0
  205. /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/references/liquid-filters.md +0 -0
@@ -0,0 +1,69 @@
1
+ # Inspecting and Validating
2
+
3
+ ## The validation pipeline
4
+
5
+ Every command validates the config on load, in this order:
6
+
7
+ 1. The kernel merges all layers (any layer failure names the file).
8
+ 2. The legacy-schema guard rejects the removed multi-project keys (`projects`,
9
+ `defaultProject`) with a migration message.
10
+ 3. A strict schema validates the merged result: unknown keys at ANY level are rejected with the
11
+ full path and a typo hint; a target must have exactly one of `entryPoint` / `entryGlob`;
12
+ `version`, when present, must be `1` (anything else fails as unsupported by this sous
13
+ version).
14
+ 4. Variable resolution and substitution run as values are used; `sous config validate` runs them
15
+ eagerly (below).
16
+
17
+ Validation applies to the MERGED config only. A `conf.d/` fragment on its own does not need to
18
+ be a complete config; it only needs to use schema-known keys.
19
+
20
+ ## The JSON Schema artifact
21
+
22
+ Sous ships `sous.config.schema.json` at the package root (generated from the same schema that
23
+ validates at load time). A JSON config can bind it for editor autocompletion and external
24
+ tooling:
25
+
26
+ ```json
27
+ { "$schema": "./path/to/sous.config.schema.json" }
28
+ ```
29
+
30
+ The `$schema` key is accepted at the top level and ignored by sous itself.
31
+
32
+ ## sous config show
33
+
34
+ Prints the full merged config as pretty JSON: the config as written, after layer merging but
35
+ BEFORE variable resolution. Output is machine-readable by contract: the decorative header and
36
+ any error text go to stderr, so `sous config show | jq .` always receives either valid JSON or
37
+ nothing. Colorized only when stdout is a TTY.
38
+
39
+ ## sous config get
40
+
41
+ Prints one value by dot-path, with `[n]` for array indices:
42
+
43
+ ```bash
44
+ sous config get name
45
+ sous config get compilation.targets[0].entryPoint
46
+ ```
47
+
48
+ Scalars print raw (no quotes); objects and arrays print as pretty JSON. A missing path exits
49
+ non-zero with a message on stderr.
50
+
51
+ `--layers` adds provenance: for each loaded layer whose cumulative merge CHANGED the value at
52
+ that path, one line prints the layer file and the old and new values, starting from `(unset)`.
53
+ This answers "which file set this?" directly:
54
+
55
+ ```bash
56
+ sous config get tools.claude.command --layers
57
+ ```
58
+
59
+ ## sous config validate
60
+
61
+ Runs the whole pipeline eagerly: discovery, kernel merge, legacy guard, schema, then FULL
62
+ variable resolution including compilation, tools and watch config. This surfaces the errors
63
+ schema validation alone cannot: variable cycles, undefined `${refs}`, and bad substitutions in
64
+ entry points and destinations. On success it prints a short summary (config file, layer count,
65
+ target count, tools) and exits 0; on failure it prints the `ConfigError` and exits non-zero.
66
+
67
+ All three commands honor the same config-locating flags and env vars as every other command
68
+ (`--config`/`-c`/`--sous-config`, `--sous-dir`, `--sous-confd`, `SOUS_CONFIG`, `SOUS_DIR`,
69
+ `SOUS_CONFD`); see [Discovery and overrides](config-discovery.md).
@@ -0,0 +1,92 @@
1
+ # Layers and Merging
2
+
3
+ Every config source (the primary file plus each `conf.d/` layer) is loaded by one subprocess,
4
+ the config kernel, which merges everything into a single cumulative config and returns it as
5
+ plain JSON.
6
+
7
+ ## Load order
8
+
9
+ 1. The primary `sous.config.*` file.
10
+ 2. Every `*.js|mjs|json|jsonc|yaml` file directly inside `conf.d/` (non-recursive), sorted BYTEWISE
11
+ by filename. The sort is locale-independent and per-machine stable, but it is not numeric:
12
+ `10-a.json` sorts before `2-b.json` because the character `1` precedes `2`. Zero-pad numeric
13
+ prefixes (`02-`, `10-`) when ordering matters.
14
+
15
+ A `.jsonc` layer is JSON with comments: line comments, block comments and trailing commas are all
16
+ allowed in it, and it merges exactly like a `.json` one. The layers sous manages for you are
17
+ written that way, so each can say in the file itself what it holds.
18
+
19
+ ## JSON forcing
20
+
21
+ Each layer's contribution passes through a JSON round-trip BEFORE merging:
22
+
23
+ - Functions and `undefined` values are dropped.
24
+ - `RegExp` becomes `{}`; `Date` becomes its ISO string.
25
+ - The final merged config is round-tripped once more on the way out.
26
+
27
+ Write configs as plain data; behavior belongs in `configure()` (below), which runs inside the
28
+ kernel before serialization.
29
+
30
+ ## Deep merge semantics
31
+
32
+ Applied key by key when a later layer meets the cumulative config:
33
+
34
+ - plain object + plain object: recurse
35
+ - array + array: CONCATENATE, cumulative first, layer second. No dedupe; loading the same
36
+ fragment twice duplicates its array entries. There is no declarative way to remove or replace
37
+ an array entry; use `configure()` and mutate directly when you need that.
38
+ - anything else (scalar, mixed types, null): the later layer replaces
39
+ - an own `__proto__`, `constructor`, or `prototype` key in layer data is skipped
40
+ (prototype-pollution guard)
41
+
42
+ ## The JS/MJS layer contract
43
+
44
+ A `.js` or `.mjs` layer may export a config object, a configure function, or both:
45
+
46
+ - **Object**: `export const config = {...}`, or a default export that is a non-function object.
47
+ Merged first.
48
+ - **Function**: `export function configure(currentConfig, builder)`, or a default export that is
49
+ a function. Runs AFTER the object (if any) merges. It may be async and is awaited. It may
50
+ mutate `currentConfig` by reference freely. A returned object is merged after it resolves,
51
+ UNLESS the return value IS `currentConfig` itself (the mutate-and-return-for-chaining idiom),
52
+ which is skipped so arrays are not duplicated by a self-merge.
53
+
54
+ ## The builder
55
+
56
+ `configure` receives a builder with:
57
+
58
+ - `builder.config`: the live cumulative config (same object as `currentConfig`)
59
+ - `builder.sousDir`, `builder.confDir`: resolved directories
60
+ - `builder.currentFile`: absolute path of the layer being loaded
61
+ - `builder.env(name, fallback)`: read an environment variable (env files are already loaded at
62
+ this point)
63
+ - `builder.merge(obj)`: JSON-force `obj` and deep-merge it into the cumulative config
64
+ - `builder.loadConfig(path)`: load another file (any supported extension) under the full layer
65
+ contract, including its own nested `configure`. Async.
66
+ - `builder.loadConfigs(globPattern)`: glob, sort matches bytewise, and load each. Async.
67
+
68
+ Builder path arguments resolve BEFORE variable resolution, so user `_vars` do not exist yet.
69
+ Only the auto-vars may appear in them: `${sousDir}`, `${sousConfDir}`, `${sousRootPath}`,
70
+ `${sousVersion}`. Any other `${name}` in a builder path is a hard error listing the allowed
71
+ names. Relative paths resolve against the directory of `builder.currentFile`. Load cycles (a
72
+ file loading itself, directly or indirectly) are detected and reported.
73
+
74
+ ## Failure behavior
75
+
76
+ Any layer failure (a JSON/YAML parse error, an import error, a `configure` throw, a load cycle,
77
+ the legacy multi-project schema) halts the whole load with an error naming the layer file. There
78
+ is no warn-and-skip; a broken layer never silently drops out of the merge.
79
+
80
+ ## The managed 5xx layer band
81
+
82
+ `conf.d/500-*` through `conf.d/599-*` is reserved for layers the sous CLI writes on your behalf.
83
+ They are `.jsonc`, and each one opens with a header comment saying what it holds.
84
+
85
+ **Sous edits these files by key; you may edit them too.** A write rewrites only the bytes of the
86
+ entry that changes, so your comments, your key order and your formatting survive it, and repeated
87
+ edits produce minimal version-control diffs. Sous never edits a hand-written primary config or a
88
+ layer outside the 5xx band. To override a managed value rather than change it in place, add a
89
+ higher-sorting layer (for example `conf.d/600-overrides.json`).
90
+
91
+ Where a comment is impossible because a format really is strict JSON, the convention is a `//`
92
+ key, which sous ignores wherever it appears.
@@ -0,0 +1,79 @@
1
+ # Variables
2
+
3
+ How `${var}` references resolve inside a sous config.
4
+
5
+ ?> Template files use LiquidJS double-brace syntax instead; that is a different stage entirely.
6
+ This page is about the config side only.
7
+
8
+ ## The scope chain
9
+
10
+ Later scopes override earlier ones:
11
+
12
+ ```
13
+ auto-vars -> _env scope -> _vars -> compilation._vars -> target._vars -> output._vars
14
+ ```
15
+
16
+ Nested `_vars` blocks (on `compilation`, on a target, on an output) resolve with their parent
17
+ scope inherited, so a target var may reference a top-level var, and an output var may override
18
+ both for that output only.
19
+
20
+ ## Auto-vars
21
+
22
+ Always injected first, before `_env` and `_vars`:
23
+
24
+ | Variable | Value |
25
+ |----------|-------|
26
+ | `sousDir` | the discovered `.sous/` directory holding the active config |
27
+ | `sousConfDir` | the `conf.d/` drop-in directory for the active config |
28
+ | `sousConfigPath` | absolute path of the active primary config file |
29
+ | `sousRootPath` | absolute path of the sous CLI install directory |
30
+ | `sousVersion` | the sous CLI version string |
31
+ | `sousTemplatePath` | absolute path of the `.tpl.` file being rendered (render time only) |
32
+ | `sousTemplateDir` | directory of the `.tpl.` file being rendered (render time only) |
33
+
34
+ The `sous*` namespace is reserved: defining any var whose name starts with `sous` earns a
35
+ warning and risks colliding with a future auto-var.
36
+
37
+ ## _env
38
+
39
+ The top-level-only `_env` block maps config var names to environment variable names:
40
+ `_env: { userHome: "HOME" }` makes `${userHome}` available everywhere. Values come from the real
41
+ shell environment, `.sous/.env.local`, or `.sous/.env` (first writer wins, in that order). A
42
+ mapped env var that is not set anywhere is a hard `ConfigError` telling you which file to define
43
+ it in.
44
+
45
+ ## Fixpoint resolution
46
+
47
+ Each `_vars` block resolves by a fixpoint loop, not top-to-bottom: every round re-scans the
48
+ still-unresolved entries and finalizes any whose `${refs}` all resolve, repeating until a round
49
+ finalizes nothing. Declaration order therefore never matters; `{ file: "${root}/x", root:
50
+ "/data" }` resolves as readily as the reverse.
51
+
52
+ If entries remain unresolved when progress stops, that is a hard `ConfigError`. The message
53
+ separates:
54
+
55
+ - **Cycles**: entries that reference each other (members are named), and
56
+ - **Undefined references**: `${names}` defined nowhere (each is named along with the entries
57
+ that need it),
58
+
59
+ and then lists the variables that ARE in scope. There is no silent fallthrough: an unresolved
60
+ `${var}` never survives into a value sous acts on. Entry points, destinations, prompt files and
61
+ similar action values additionally pass a strict substitution that fails on any leftover
62
+ reference.
63
+
64
+ ## Path normalization
65
+
66
+ Absolute `entryPoint`, `entryGlob`, `globBase`, `destinationFile` and `destinationDir` values
67
+ are normalized after substitution, so the common `${sousDir}/..` idiom collapses to the real
68
+ parent directory. This matters: prune compares tracked outputs against `destinationDir` by
69
+ string prefix, and watch mode matches event paths against watched entries; both need the
70
+ normalized form.
71
+
72
+ ## Special variables sous reads
73
+
74
+ Two ordinary `_vars` entries change sous's own behavior when present:
75
+
76
+ - `stateFilePath`: overrides where the build state file is written (default
77
+ `<sousDir>/sous.state.json`)
78
+ - `pidFilePath`: overrides where the watch-mode PID file is written (default
79
+ `<sousDir>/sous.pid`)
@@ -0,0 +1,71 @@
1
+ # Configuration
2
+
3
+ Sous reads one configuration per project from the project's `.sous/` directory. One config
4
+ describes one project: every setting lives at the top level of a single flat object. There is no
5
+ user-level config (nothing is read from `~/.sous`) and no multi-project map.
6
+
7
+ ## The config file
8
+
9
+ Exactly one primary config lives inside `.sous/`: `sous.config.js`, `sous.config.mjs`,
10
+ `sous.config.json`, `sous.config.jsonc`, or `sous.config.yaml`. Two or more candidates is an
11
+ error, never a silent first-match. A typical config:
12
+
13
+ ```js
14
+ export const config = {
15
+ version: 1, // optional; must be 1 when present
16
+ name: "My Project", // optional display name
17
+ _env: { userHome: "HOME" }, // map config vars from env vars (top-level only)
18
+ _vars: {
19
+ projectRoot: "${sousDir}/..", // ${sousDir} is the discovered .sous/ dir
20
+ docsDir: "${projectRoot}/docs", // declaration order never matters
21
+ },
22
+ _aliases: { myDocs: "${docsDir}" }, // extra @include bases (optional)
23
+ compilation: {
24
+ targets: [
25
+ {
26
+ entryPoint: "${projectRoot}/prompts/AGENTS.md",
27
+ outputs: [{ destinationFile: "${projectRoot}/AGENTS.md" }],
28
+ },
29
+ {
30
+ entryGlob: "${projectRoot}/prompts/skills/**/*.md",
31
+ outputs: [{ destinationDir: "${projectRoot}/.claude/skills" }],
32
+ },
33
+ ],
34
+ },
35
+ tools: {
36
+ claude: { command: "claude", promptFile: "${projectRoot}/CLAUDE.md" },
37
+ },
38
+ };
39
+ ```
40
+
41
+ A JSON config may set `"$schema"` to bind the `sous.config.schema.json` artifact shipped with
42
+ sous for editor autocompletion; sous accepts and ignores the key.
43
+
44
+ ?> Configs use `${var}` syntax. Template files use LiquidJS double-brace syntax instead; the two
45
+ are resolved at different stages and never mix.
46
+
47
+ ## Composition
48
+
49
+ The primary config is optionally extended by drop-in layers: every `*.js|mjs|json|jsonc|yaml` file
50
+ directly inside `.sous/conf.d/` is loaded after the primary config and deep-merged over it. A
51
+ `.js`/`.mjs` config or layer can also compose programmatically through a `configure()` function.
52
+ [Layers and merging](config-layers.md) covers the full semantics.
53
+
54
+ ## Where to go next
55
+
56
+ - [Discovery and overrides](config-discovery.md): how sous finds the config, and the flags and
57
+ environment variables that override it
58
+ - [Layers and merging](config-layers.md): `conf.d/` ordering, merge semantics, the JS
59
+ `configure()` contract
60
+ - [Variables](config-variables.md): the `${var}` scope chain, auto-vars, fixpoint resolution
61
+ - [Inspecting and validating](config-inspection.md): the `sous config` commands and the
62
+ validation pipeline
63
+
64
+ ## Rules of the road
65
+
66
+ - Hand-written config belongs in the primary file or your own `conf.d/` layers. The
67
+ `conf.d/500-*` through `conf.d/599-*` band is reserved for layers the sous CLI itself writes.
68
+ Sous edits those by key, so you may edit them too and your comments, key order and formatting
69
+ survive; put a layer of your own outside the band.
70
+ - Any config problem halts sous with a `ConfigError` naming the offending file; there is no
71
+ warn-and-continue.
@@ -0,0 +1,59 @@
1
+ # Design Principles
2
+
3
+ These principles govern every feature sous ships. They are constraints on design, not
4
+ aspirations; when a proposal violates one, the proposal changes.
5
+
6
+ ## 1. Augment, don't compete
7
+
8
+ When a coding tool can do something natively, do it natively; sous exists for what the tool
9
+ cannot do. Sous never wraps, replaces, or re-implements a capability an agent harness already
10
+ provides well.
11
+
12
+ *Example: sous compiles `CLAUDE.md` and skill files because no harness composes them from
13
+ shared, templated sources; it does not try to replace how the harness loads them.*
14
+
15
+ ## 2. Fill the collective gaps
16
+
17
+ Sous actively tries to avoid competing with any tool, and especially with any class of tools.
18
+ Instead it fills the gaps that most or all tools either cannot or will not fill, because those
19
+ problems span every provider at once.
20
+
21
+ *Example: keeping one instruction source current across Claude, Codex, and whatever comes next
22
+ is nobody's product; it is sous's whole job.*
23
+
24
+ ## 3. Be a tool, not a framework
25
+
26
+ Sous avoids forcing opinions; that is different from having none. Beyond the few core skills
27
+ that teach agents how to work with sous itself, every built-in is opt-in only, and even the
28
+ core is opt-out-able.
29
+
30
+ *Example: the core skills arrive by default because agents need them to avoid editing
31
+ generated files, but a single explicit setting removes them entirely.*
32
+
33
+ ## 4. Be easy to enter
34
+
35
+ Sous copies plain files just as readily as it renders templates, so adopting it does not
36
+ require converting anything. Existing marketplaces and installers keep working, pointed at a
37
+ sous-managed directory.
38
+
39
+ *Example: drop an existing skill directory into a sous target unchanged; it compiles verbatim
40
+ on the next build.*
41
+
42
+ ## 5. Be easy to exit
43
+
44
+ Leaving sous must never cost more than a commit. The generated output is complete and ordinary;
45
+ commit it and delete `.sous`, and the project keeps working exactly as it did.
46
+
47
+ *Example: every file sous writes is a normal file in its final location; nothing references
48
+ sous at runtime.*
49
+
50
+ ## 6. Maximum user control
51
+
52
+ Everything gets an escape hatch, within practicality. The happy path stays maximally simple;
53
+ the escape hatches are advanced usage and may require the docs, but they must exist and they
54
+ still get thoughtful ergonomics. Projects control everything granularly, and an individual
55
+ user can override every project decision through their own configuration layers.
56
+
57
+ *Example: subscribing to a recipe is one line and pulls in everything the recipe provides;
58
+ excluding one skill from that subscription may take a documented setting, but the setting is
59
+ there.*