@ontrails/config 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,366 @@
1
+ # @ontrails/config
2
+
3
+ ## 0.2.0
4
+
5
+ ### Patch Changes
6
+
7
+ - [`664e8bb`](https://github.com/outfitter-dev/trails/commit/664e8bb049e61f1d47cec1dd246606707af5d1a8): Point public installation examples at exact approved 0.2.0 versions and distinguish the prepared source release from pending npm publication.
8
+ - [`b3ddf91`](https://github.com/outfitter-dev/trails/commit/b3ddf918ada8211f44983512e2bbdfbc5b66d722): Prepare the first normal Trails release at `0.2.0` on `latest`, replacing the unpublished 1.0.0 source release. The target advances the original `0.1.0` source minor, which was never published under the current package names. Public packages remain in lockstep. Update consumer installation guidance and provide a temporary manifest bridge for old 1.0 beta sources. Published beta versions remain unchanged; minor 0.x releases may carry documented breaking changes.
9
+
10
+ The `1.0.0` section retained below records an unpublished preparation, not an npm release. Its accumulated changes are included in `0.2.0`; the section remains as source history alongside the published beta entries.
11
+
12
+ ## 1.0.0
13
+
14
+ ### Major Changes
15
+
16
+ - [`10eae9a`](https://github.com/outfitter-dev/trails/commit/10eae9a96079dde67227191f670ba7ed1b40fef2): Migrate the Trails workspace to the documented `.trails/` layout: committed `.lock` files at the workspace root, ignored `cache/` for rebuildable derived data, ignored `state/` for mutable runtime state, and `.trails/config.local.{ts,js}` for local overrides. The default SQLite path is now `.trails/state/trails.db`. Workspace bootstrap creates only `cache/` and `state/` — the legacy `dev/` and `generated/` subdirectories are no longer created. Dev reset cleans both the new `.trails/state/` paths and legacy `.trails/trails.db*` and `.trails/dev/tracing.db*` paths for one cycle. Scaffold and workspace gitignores reflect the new layout.
17
+
18
+ Workspace bootstrap is now owned by a single canonical source in `@ontrails/core`. The package exposes `ensureTrailsWorkspace()`, `WORKSPACE_GITIGNORE_CONTENT`, and `WORKSPACE_GITIGNORE_LINES`. `@ontrails/config` no longer exports its own `ensureWorkspace` (consumers should import from `@ontrails/core`). `trails create` now writes `.trails/.gitignore` during scaffolding so a fresh-scaffolded project's initial commit includes the workspace gitignore (resolves TRL-703).
19
+
20
+ ### Minor Changes
21
+
22
+ - [`6944147`](https://github.com/outfitter-dev/trails/commit/694414712949a1107235684a2492ac982ed39a20): Complete trifecta for config, permits, and tracker (formerly tracks)
23
+
24
+ - **config**: Add `configResource`, `config.trail`, and `config.workspace` trails with full `defineConfig`, `resolve`, `describe`, `explain`, `doctor`, and code generation support
25
+ - **permits**: Add `authResource` and `auth.verify` trail for runtime authorization checks
26
+ - **tracing**: Rename tracks to tracing; add `tracingResource` and `tracing.status` trail for structured signal tracking
27
+ - **cli**: Fix build flag handling and improve bootstrap scaffolding
28
+ - **testing**: Expand test context helpers and example-based testing utilities
29
+ - **core/mcp/http**: Internal alignment for resource and composition updates
30
+
31
+ - [`69057e9`](https://github.com/outfitter-dev/trails/commit/69057e9348006b2b70c9f6237572a5aa8de3ee1f): Add hierarchical CLI command trees and structured input, enforce established-only topo exports across surfaces, move developer topo and tracing state onto shared `trails.db` with pins and maintenance flows, and ship schema-derived stores through `@ontrails/store` and its Drizzle runtime.
32
+ - [`1679687`](https://github.com/outfitter-dev/trails/commit/1679687219431c38cdc7f46de8de60ccac49fd3c): Add Config-owned static `workspace.apps` identity with bounded, non-executing TypeScript extraction, shared data-format validation, convention-derived app entries, and normalized project paths. Type-only wrappers remain transparent, unrelated deployment expressions stay outside identity proof, duplicate identity keys fail before parser collapse, separator aliases cannot create competing app-root owners, and Source preserves declared submodule boundaries when their checkouts are absent. YAML workspace identity must stay literal, JSON-compatible data: alias references and merge keys inside the workspace subtree now fail closed before identity resolution instead of collapsing silently at parse time, while an anchor definition that nothing references stays inert and cannot alter the resolved identity. Invalid discovery start directories also fail closed: a start path that is missing or is not a directory now raises a typed `ValidationError` naming it instead of silently walking up to an ancestor project's identity.
33
+ - [`5adb995`](https://github.com/outfitter-dev/trails/commit/5adb99551c2dda6190d46cce7f60bb08d63c99aa): Complete the v1 hard cutover from the authored `blaze` field to
34
+ `implementation` across trail contracts, surface projections, tests, examples,
35
+ and public source-analysis helpers. Existing applications must rename authored
36
+ trail behavior fields and direct trail-object access before upgrading.
37
+ - [`fde5516`](https://github.com/outfitter-dev/trails/commit/fde5516ad396faa718936b10ff658b3ade3383b9): Trail-native vocabulary cutover. Breaking API field renames across all packages:
38
+
39
+ - Trail spec: `run:` → `blaze:`, `follow:` → `crosses:`, `services:` → `resources:`, `metadata:` → `meta:`, `emits:` → `fires:`
40
+ - Runtime: `ctx.follow()` → `ctx.cross()`, `ctx.emit()` → `ctx.fire()`, `ctx.signal` (abort) → `ctx.abortSignal`
41
+ - Entry points: `trailhead(app)` → `surface(app)`
42
+ - Package rename: `@ontrails/crumbs` / `@ontrails/tracker` → `@ontrails/tracing`
43
+ - Wrapper types: retired gate/middleware vocabulary in favor of `Layer` and `layers`
44
+ - Package taxonomy: retired connector vocabulary in favor of adapters
45
+
46
+ - [`082408e`](https://github.com/outfitter-dev/trails/commit/082408e32c16fd737d8899fc8c8a51fa0f61b3d9): Warn when a configured workspace contains a nested `trails.lock` outside `workspace.apps`, and reject a workspace-root aggregate lock without deriving app identity from either artifact.
47
+
48
+ Make the Trails operator topo reproducible by keeping its authored examples free of temporary filesystem paths, so its committed app-owned lock validates deterministically.
49
+
50
+ Replay known operator current-app examples through the selected Config entry, including the nested project input in the authored `run` example, so custom app layouts do not fall back to `src/app.ts` without rewriting matching fields in domain examples.
51
+
52
+ Add `trails config explain` as the operator-owned inspection surface for source-static project and app identity. It reports the Config-authored catalog, selected extent, and selection provenance without loading app modules or reading locks.
53
+
54
+ **BREAKING:** Remove the public `@ontrails/config` `configExplain` trail export. Library consumers that inspect resolved deployment provenance must migrate to `deriveConfigProvenance`; operators and agents that inspect Config-authored app identity must migrate to `trails config explain`. The broader config cascade stays deferred.
55
+
56
+ ### Patch Changes
57
+
58
+ - [`3dc8254`](https://github.com/outfitter-dev/trails/commit/3dc82547f428bcb6adb7eac1201a0c87cf63b8af): Fix README TypeScript snippets so the expanded documentation snippet gate can verify them.
59
+ - [`49c2e7d`](https://github.com/outfitter-dev/trails/commit/49c2e7d5c7c063b9aa6abee1d2932bf3003133cc): Refresh published package README taxonomy to use adapter language instead of retired connector vocabulary.
60
+ - [`1307568`](https://github.com/outfitter-dev/trails/commit/13075680e1c77c0a3abee36aaecce8cecad2f347): Centralize Trails config module path conventions, move local config overrides to root `trails.config.local.*`, scaffold the matching gitignore entries, and load project-local Warden rules from `.trails/rules.ts` or `.trails/rules/`.
61
+ - [`ef09e46`](https://github.com/outfitter-dev/trails/commit/ef09e4673563fc3b763fef3df510b34d67c45fe1): Add shared Trails project-root discovery helpers and use them in Warden so nested
62
+ cwd invocations still load root `trails.config.*` and project-local
63
+ `.trails/rules*` governance.
64
+ - [`38cd9d6`](https://github.com/outfitter-dev/trails/commit/38cd9d63ad40ae45986f6bdb01109f383b3a19ab): Add a shared Trails config file loader that treats `trails.config.ts` as the natural primary while supporting JSON, JSONC, YAML, and TOML peer formats. Release and Warden config loading now consume the same loader and local overrides can be authored as data files.
65
+ - [`2b819f4`](https://github.com/outfitter-dev/trails/commit/2b819f4f805737439844af29a7c411d4af7c0bba): Rename config check reports to `ConfigReport` and `ConfigFieldReport`, and return field reports from `config.check`.
66
+ - [`b1fbe57`](https://github.com/outfitter-dev/trails/commit/b1fbe574e6f44d1fecb5e3a000270955c0a77b7b): Publish Bun-validated package tarballs through an npm trusted-publishing adapter
67
+ binding, add exact repository metadata for each public workspace package, and
68
+ correct the native Bun release descriptor to its pack-only runtime boundary.
69
+ - [`1e168b1`](https://github.com/outfitter-dev/trails/commit/1e168b16caa5014f641fea37d028820211fb2ae1): Resolve one shared project context for `trails compile` and `trails validate`.
70
+ Configured workspaces now select apps through `--app` or app-root CWD, compile
71
+ exactly one app lock without root fanout, validate either one app or the complete
72
+ workspace, enforce configured topo-name binding and collection boundaries, and
73
+ return machine-readable selection and completeness provenance. Project-root
74
+ discovery can now be bounded to one working tree so linked and nested checkouts
75
+ do not borrow identity from a parent collection. Without Git metadata the
76
+ boundary walk continues to the outermost workspace declaration, so nested or
77
+ overlapping workspaces fail closed with a typed error naming both roots instead
78
+ of silently selecting the nearest one. Custom `--module` entries stay
79
+ relative to the selected standalone app root, and complete workspace validation
80
+ derives saved binding and freshness evidence once after validating each live app.
81
+ - [`99523f2`](https://github.com/outfitter-dev/trails/commit/99523f2a67e92091781165b6c847252b910554e2): Clean up resource context naming in shipped source and examples so resource
82
+ factories consistently use resource vocabulary.
83
+
84
+ ## 1.0.0-beta.50
85
+
86
+ ## 1.0.0-beta.49
87
+
88
+ ## 1.0.0-beta.48
89
+
90
+ ## 1.0.0-beta.47
91
+
92
+ ## 1.0.0-beta.46
93
+
94
+ ## 1.0.0-beta.45
95
+
96
+ ## 1.0.0-beta.44
97
+
98
+ ### Patch Changes
99
+
100
+ - [`b1fbe57`](https://github.com/outfitter-dev/trails/commit/b1fbe574e6f44d1fecb5e3a000270955c0a77b7b): Publish Bun-validated package tarballs through an npm trusted-publishing adapter
101
+ binding, add exact repository metadata for each public workspace package, and
102
+ correct the native Bun release descriptor to its pack-only runtime boundary.
103
+
104
+ ## 1.0.0-beta.43
105
+
106
+ ## 1.0.0-beta.42
107
+
108
+ ## 1.0.0-beta.41
109
+
110
+ ## 1.0.0-beta.40
111
+
112
+ ### Minor Changes
113
+
114
+ - [`5adb995`](https://github.com/outfitter-dev/trails/commit/5adb99551c2dda6190d46cce7f60bb08d63c99aa): Complete the v1 hard cutover from the authored `blaze` field to
115
+ `implementation` across trail contracts, surface projections, tests, examples,
116
+ and public source-analysis helpers. Existing applications must rename authored
117
+ trail behavior fields and direct trail-object access before upgrading.
118
+
119
+ ## 1.0.0-beta.39
120
+
121
+ ## 1.0.0-beta.38
122
+
123
+ ## 1.0.0-beta.37
124
+
125
+ ## 1.0.0-beta.36
126
+
127
+ ## 1.0.0-beta.35
128
+
129
+ ## 1.0.0-beta.34
130
+
131
+ ## 1.0.0-beta.33
132
+
133
+ ## 1.0.0-beta.32
134
+
135
+ ### Patch Changes
136
+
137
+ - 2b819f4: Rename config check reports to `ConfigReport` and `ConfigFieldReport`, and return field reports from `config.check`.
138
+ - Updated dependencies [3e5c0fc]
139
+ - Updated dependencies [f3c4fef]
140
+ - Updated dependencies [cb0a9d8]
141
+ - Updated dependencies [21c6dda]
142
+ - Updated dependencies [fe72b84]
143
+ - @ontrails/core@1.0.0-beta.32
144
+
145
+ ## 1.0.0-beta.31
146
+
147
+ ### Patch Changes
148
+
149
+ - Updated dependencies [4cd5d4e]
150
+ - Updated dependencies [38907cc]
151
+ - @ontrails/core@1.0.0-beta.31
152
+
153
+ ## 1.0.0-beta.30
154
+
155
+ ### Patch Changes
156
+
157
+ - @ontrails/core@1.0.0-beta.30
158
+
159
+ ## 1.0.0-beta.29
160
+
161
+ ### Patch Changes
162
+
163
+ - @ontrails/core@1.0.0-beta.29
164
+
165
+ ## 1.0.0-beta.28
166
+
167
+ ### Patch Changes
168
+
169
+ - @ontrails/core@1.0.0-beta.28
170
+
171
+ ## 1.0.0-beta.27
172
+
173
+ ### Patch Changes
174
+
175
+ - @ontrails/core@1.0.0-beta.27
176
+
177
+ ## 1.0.0-beta.26
178
+
179
+ ### Patch Changes
180
+
181
+ - 1307568: Centralize Trails config module path conventions, move local config overrides to root `trails.config.local.*`, scaffold the matching gitignore entries, and load project-local Warden rules from `.trails/rules.ts` or `.trails/rules/`.
182
+ - ef09e46: Add shared Trails project-root discovery helpers and use them in Warden so nested
183
+ cwd invocations still load root `trails.config.*` and project-local
184
+ `.trails/rules*` governance.
185
+ - 38cd9d6: Add a shared Trails config file loader that treats `trails.config.ts` as the natural primary while supporting JSON, JSONC, YAML, and TOML peer formats. Release and Warden config loading now consume the same loader and local overrides can be authored as data files.
186
+ - Updated dependencies [1307568]
187
+ - Updated dependencies [371d19e]
188
+ - @ontrails/core@1.0.0-beta.26
189
+
190
+ ## 1.0.0-beta.25
191
+
192
+ ### Patch Changes
193
+
194
+ - Updated dependencies [c36aca9]
195
+ - Updated dependencies [3befcf1]
196
+ - Updated dependencies [a4f9cf6]
197
+ - Updated dependencies [9bcf34e]
198
+ - @ontrails/core@1.0.0-beta.25
199
+
200
+ ## 1.0.0-beta.24
201
+
202
+ ### Patch Changes
203
+
204
+ - @ontrails/core@1.0.0-beta.24
205
+
206
+ ## 1.0.0-beta.23
207
+
208
+ ### Patch Changes
209
+
210
+ - @ontrails/core@1.0.0-beta.23
211
+
212
+ ## 1.0.0-beta.22
213
+
214
+ ### Patch Changes
215
+
216
+ - @ontrails/core@1.0.0-beta.22
217
+
218
+ ## 1.0.0-beta.21
219
+
220
+ ### Patch Changes
221
+
222
+ - 99523f2: Clean up resource context naming in shipped source and examples so resource
223
+ factories consistently use resource vocabulary.
224
+ - Updated dependencies [99523f2]
225
+ - @ontrails/core@1.0.0-beta.21
226
+
227
+ ## 1.0.0-beta.20
228
+
229
+ ### Patch Changes
230
+
231
+ - Updated dependencies [851a2a3]
232
+ - @ontrails/core@1.0.0-beta.20
233
+
234
+ ## 1.0.0-beta.19
235
+
236
+ ### Patch Changes
237
+
238
+ - Updated dependencies [e41c382]
239
+ - Updated dependencies [1eb5bdc]
240
+ - Updated dependencies [f8d80b9]
241
+ - Updated dependencies [846a597]
242
+ - Updated dependencies [223aaad]
243
+ - Updated dependencies [3125f4d]
244
+ - Updated dependencies [2494dc6]
245
+ - Updated dependencies [2d53717]
246
+ - Updated dependencies [16cb740]
247
+ - Updated dependencies [8894ecb]
248
+ - Updated dependencies [fdf7ec9]
249
+ - Updated dependencies [d76be13]
250
+ - Updated dependencies [84f56a5]
251
+ - Updated dependencies [431b04c]
252
+ - Updated dependencies [5d88104]
253
+ - Updated dependencies [f04a9ef]
254
+ - @ontrails/core@1.0.0-beta.19
255
+
256
+ ## 1.0.0-beta.18
257
+
258
+ ### Patch Changes
259
+
260
+ - @ontrails/core@1.0.0-beta.18
261
+
262
+ ## 1.0.0-beta.17
263
+
264
+ ### Patch Changes
265
+
266
+ - 3dc8254: Fix README TypeScript snippets so the expanded documentation snippet gate can verify them.
267
+ - Updated dependencies [3dc8254]
268
+ - @ontrails/core@1.0.0-beta.17
269
+
270
+ ## 1.0.0-beta.16
271
+
272
+ ### Major Changes
273
+
274
+ - 10eae9a: Migrate the Trails workspace to the documented `.trails/` layout: committed `.lock` files at the workspace root, ignored `cache/` for rebuildable derived data, ignored `state/` for mutable runtime state, and `.trails/config.local.{ts,js}` for local overrides. The default SQLite path is now `.trails/state/trails.db`. Workspace bootstrap creates only `cache/` and `state/` — the legacy `dev/` and `generated/` subdirectories are no longer created. Dev reset cleans both the new `.trails/state/` paths and legacy `.trails/trails.db*` and `.trails/dev/tracing.db*` paths for one cycle. Scaffold and workspace gitignores reflect the new layout.
275
+
276
+ Workspace bootstrap is now owned by a single canonical source in `@ontrails/core`. The package exposes `ensureTrailsWorkspace()`, `WORKSPACE_GITIGNORE_CONTENT`, and `WORKSPACE_GITIGNORE_LINES`. `@ontrails/config` no longer exports its own `ensureWorkspace` (consumers should import from `@ontrails/core`). `trails create` now writes `.trails/.gitignore` during scaffolding so a fresh-scaffolded project's initial commit includes the workspace gitignore (resolves TRL-703).
277
+
278
+ ### Patch Changes
279
+
280
+ - 49c2e7d: Refresh published package README taxonomy to use adapter language instead of retired connector vocabulary.
281
+ - Updated dependencies [73622ae]
282
+ - Updated dependencies [6300f70]
283
+ - Updated dependencies [d172013]
284
+ - Updated dependencies [c3fc5c3]
285
+ - Updated dependencies [20d7a5c]
286
+ - Updated dependencies [be5fb46]
287
+ - Updated dependencies [e898cc4]
288
+ - Updated dependencies [3395234]
289
+ - Updated dependencies [bcdc484]
290
+ - Updated dependencies [331e3a9]
291
+ - Updated dependencies [4399fdb]
292
+ - Updated dependencies [4b8d13b]
293
+ - Updated dependencies [112b9f2]
294
+ - Updated dependencies [893025e]
295
+ - Updated dependencies [eec5e9d]
296
+ - Updated dependencies [ebd4434]
297
+ - Updated dependencies [863d473]
298
+ - Updated dependencies [344f2f7]
299
+ - Updated dependencies [26f9ffd]
300
+ - Updated dependencies [10eae9a]
301
+ - Updated dependencies [22c6c06]
302
+ - @ontrails/core@1.0.0-beta.16
303
+
304
+ ## 1.0.0-beta.15
305
+
306
+ ### Patch Changes
307
+
308
+ - Updated dependencies [4ad6b25]
309
+ - @ontrails/core@1.0.0-beta.15
310
+
311
+ ## 1.0.0-beta.14
312
+
313
+ ### Minor Changes
314
+
315
+ - 69057e9: Add hierarchical CLI command trees and structured input, enforce established-only topo exports across trailheads, move developer topo and tracker state onto shared `trails.db` with pins and maintenance flows, and ship schema-derived stores through `@ontrails/store` and its Drizzle runtime.
316
+
317
+ ### Patch Changes
318
+
319
+ - Updated dependencies [69057e9]
320
+ - @ontrails/core@1.0.0-beta.14
321
+
322
+ ## 1.0.0-beta.13
323
+
324
+ ### Minor Changes
325
+
326
+ - 6944147: Complete trifecta for config, permits, and tracker (formerly tracks)
327
+
328
+ - **config**: Add `configProvision`, `configGate`, `config.trail`, and `config.workspace` trails with full `defineConfig`, `resolve`, `describe`, `explain`, `doctor`, and code generation support
329
+ - **permits**: Add `authService` and `auth.verify` trail for runtime authorization checks
330
+ - **tracker**: Rename tracks to tracker; add `trackerProvision` and `tracker.status` trail for structured signal tracking
331
+ - **cli**: Fix build flag handling and improve bootstrap scaffolding
332
+ - **testing**: Expand test context helpers and example-based testing utilities
333
+ - **core/mcp/http**: Internal alignment for provision and composition updates
334
+
335
+ - Trail-native vocabulary cutover. Breaking API field renames across all packages:
336
+
337
+ - Trail spec: `run:` → `blaze:`, `follow:` → `crosses:`, `services:` → `provisions:`, `metadata:` → `meta:`, `emits:` → `signals:`
338
+ - Runtime: `ctx.follow()` → `ctx.cross()`, `ctx.emit()` → `ctx.signal()`, `ctx.signal` (abort) → `ctx.abortSignal`
339
+ - Entry points: `blaze(app)` → `trailhead(app)`
340
+ - Package rename: `@ontrails/crumbs` → `@ontrails/tracker`
341
+ - Wrapper types: `Layer` → `Gate`, `layers`/`middleware` → `gates`
342
+ - Transport: `surface` → `trailhead`, `adapter` → `connector`
343
+
344
+ ### Patch Changes
345
+
346
+ - Updated dependencies [6944147]
347
+ - Updated dependencies
348
+ - @ontrails/core@1.0.0-beta.13
349
+
350
+ ## 1.0.0-beta.12
351
+
352
+ ### Minor Changes
353
+
354
+ - Complete trifecta for config, permits, and tracker (formerly tracks)
355
+
356
+ - **config**: Add `configProvision`, `config.gate`, `config.trail`, and `config.workspace` trails with full `defineConfig`, `resolve`, `describe`, `explain`, `doctor`, and code generation support
357
+ - **permits**: Add `authProvision` and `auth.verify` trail for runtime authorization checks
358
+ - **tracker**: Rename tracks to tracker; add `trackerProvision` and `tracker.status` trail for structured event tracking
359
+ - **cli**: Fix build flag handling and improve bootstrap scaffolding
360
+ - **testing**: Expand test context helpers and example-based testing utilities
361
+ - **core/mcp/http**: Internal alignment for provision and composition updates
362
+
363
+ ### Patch Changes
364
+
365
+ - Updated dependencies
366
+ - @ontrails/core@1.0.0-beta.12
package/README.md ADDED
@@ -0,0 +1,262 @@
1
+ # @ontrails/config
2
+
3
+ Schema-derived configuration for Trails.
4
+
5
+ The root package owns the runtime-agnostic config declaration and resolution engine. Schemas define the contract, and `configResource` exposes resolved values to trail execution.
6
+
7
+ ## The core pattern
8
+
9
+ ### 1. Define the config schema
10
+
11
+ ```typescript
12
+ import { defineConfig, env, secret } from '@ontrails/config';
13
+ import { z } from 'zod';
14
+
15
+ export const config = defineConfig({
16
+ schema: z.object({
17
+ port: z.number().default(3000),
18
+ host: z.string().default('localhost'),
19
+ database: z.object({
20
+ url: env(secret(z.string()), 'DATABASE_URL'),
21
+ }),
22
+ debug: z.boolean().default(false),
23
+ }),
24
+ base: {
25
+ host: 'example.com',
26
+ },
27
+ profiles: {
28
+ production: {
29
+ debug: false,
30
+ host: 'prod.example.com',
31
+ port: 443,
32
+ },
33
+ test: {
34
+ debug: true,
35
+ port: 0,
36
+ },
37
+ },
38
+ });
39
+ ```
40
+
41
+ ### 2. Resolve the config at bootstrap
42
+
43
+ ```typescript
44
+ import { registerConfigState } from '@ontrails/config';
45
+
46
+ const result = await config.resolve({
47
+ cwd: process.cwd(),
48
+ profile: process.env.TRAILS_ENV,
49
+ });
50
+
51
+ if (!result.isOk()) {
52
+ throw result.error;
53
+ }
54
+
55
+ registerConfigState({
56
+ resolved: result.unwrap(),
57
+ schema: config.schema,
58
+ base: config.base,
59
+ profile: process.env.TRAILS_ENV,
60
+ env: process.env,
61
+ });
62
+ ```
63
+
64
+ ### 3. Access resolved config in trails
65
+
66
+ ```typescript
67
+ import { configResource } from '@ontrails/config';
68
+
69
+ export const getStatus = trail('status.get', {
70
+ resources: [configResource],
71
+ implementation: (_input, ctx) => {
72
+ const state = configResource.from(ctx);
73
+ return Result.ok({
74
+ port: state.resolved.port,
75
+ debug: state.resolved.debug,
76
+ });
77
+ },
78
+ });
79
+ ```
80
+
81
+ ## Resolution stack
82
+
83
+ Config resolves through a deterministic priority order:
84
+
85
+ ```text
86
+ defaults (schema) → base → profile → local → env
87
+ ```
88
+
89
+ Each layer overrides the previous. Environment variables always win.
90
+
91
+ `appConfig()` discovers `*.config.toml`, `*.config.json`, `*.config.jsonc`, and `*.config.yaml` by default, plus dotfile equivalents when `dotfile: true`.
92
+
93
+ ## Trails project roots
94
+
95
+ `@ontrails/config` owns the shared project-root convention helpers used by framework tools. `resolveTrailsProjectRoot()` honors an explicit root first, then walks upward from a start directory looking for committed project markers:
96
+
97
+ - `trails.config.ts`, `.mts`, `.js`, `.mjs`, `.json`, `.jsonc`,
98
+ `.yaml`, or `.toml`
99
+ - `trails.lock`
100
+ - source-shaped projects with `src/trails/` or `trails/` when no committed marker exists above them
101
+
102
+ `trails.config.local.*` is a per-developer override and does not mark a project root by itself. A bare `.trails/` directory also does not mark a root; it is the committed-control home for project-local sections after a project root is known.
103
+
104
+ ## Workspace app identity
105
+
106
+ A workspace root names its lock-owning Trails apps in the static `workspace.apps` section. App IDs are the authored identity, roots are project-relative, and an `entry` override is app-root-relative. Omit `entry` when the app uses the shared `src/app.ts` convention:
107
+
108
+ ```typescript
109
+ import { defineConfig } from '@ontrails/config';
110
+ import { z } from 'zod';
111
+
112
+ export default defineConfig({
113
+ schema: z.object({}),
114
+ workspace: {
115
+ apps: {
116
+ demo: { root: 'apps/demo' },
117
+ junction: { root: 'examples/junction' },
118
+ custom: { root: 'apps/custom', entry: 'src/custom-app.ts' },
119
+ },
120
+ },
121
+ });
122
+ ```
123
+
124
+ A workspace-only root may use a direct object without inventing a deployment schema:
125
+
126
+ ```typescript
127
+ export default {
128
+ workspace: {
129
+ apps: {
130
+ demo: { root: 'apps/demo' },
131
+ },
132
+ },
133
+ };
134
+ ```
135
+
136
+ `readTrailsProjectIdentity()` reads only this literal project-identity subset. TypeScript modules are parsed without being imported or evaluated; type-only wrappers such as `as const` and `satisfies` are transparent, while unrelated deployment properties remain free to use the normal resolved-config patterns before the explicit `workspace` declaration. JSON, JSONC, YAML, and TOML configs converge through the same validator. Dynamic app declarations, duplicate identity keys, escaping paths, normalized root collisions, potential overrides after `workspace`, and nested workspace declarations fail with typed `ValidationError` diagnostics.
137
+
138
+ Callers must supply their collection boundary; Config does not infer a working-tree boundary. Pass `startDir` as well when discovery starts below that root. Discovery walks past app-local locks and ordinary nested app configs, inventories workspace declarations throughout the collection, and never crosses the supplied boundary or a nested repository edge:
139
+
140
+ ```typescript
141
+ import { readTrailsProjectIdentity } from '@ontrails/config';
142
+
143
+ const workspaceRoot = '/path/to/workspace';
144
+ const identity = await readTrailsProjectIdentity({
145
+ boundaryDir: workspaceRoot,
146
+ startDir: process.cwd(),
147
+ });
148
+ ```
149
+
150
+ Each resolved app preserves the app-relative `entry` and derives its project-relative `modulePath`, absolute `rootDir` and `entryPath`, and whether the entry came from convention or an explicit override. Only authored IDs, roots, and optional entry overrides are project identity; absolute paths are live convenience values.
151
+
152
+ ## Extensions
153
+
154
+ ### `env()`
155
+
156
+ Bind a schema field to an environment variable:
157
+
158
+ ```typescript
159
+ import { env } from '@ontrails/config';
160
+
161
+ const schema = z.object({
162
+ database: env(z.string(), 'DATABASE_URL'),
163
+ port: env(z.number(), 'PORT').default(3000),
164
+ });
165
+ ```
166
+
167
+ Environment variables are coerced to the schema type. Apply `env()` before `.default()` so metadata lives on the inner type.
168
+
169
+ ### `secret()`
170
+
171
+ Mark a schema field as sensitive:
172
+
173
+ ```typescript
174
+ import { env, secret } from '@ontrails/config';
175
+
176
+ const schema = z.object({
177
+ apiKey: secret(z.string()),
178
+ password: secret(env(z.string(), 'DB_PASSWORD')),
179
+ });
180
+ ```
181
+
182
+ Secret fields are redacted in explain output, diagnostics, and logs.
183
+
184
+ ### `deprecated()`
185
+
186
+ Mark a field as deprecated with migration guidance:
187
+
188
+ ```typescript
189
+ import { deprecated } from '@ontrails/config';
190
+
191
+ const schema = z.object({
192
+ oldField: deprecated(z.string(), 'Use newField instead'),
193
+ newField: z.string(),
194
+ });
195
+ ```
196
+
197
+ ## The resource
198
+
199
+ The config resource manages resolved config lifecycle:
200
+
201
+ ```typescript
202
+ import { configResource } from '@ontrails/config';
203
+
204
+ export const myTrail = trail('my.trail', {
205
+ resources: [configResource],
206
+ implementation: (_input, ctx) => {
207
+ const state = configResource.from(ctx);
208
+ return Result.ok(state.resolved);
209
+ },
210
+ });
211
+ ```
212
+
213
+ ## Trail definitions
214
+
215
+ ### `config.check`
216
+
217
+ Validate config values against the schema. Returns a config report with field-level status (valid, missing, invalid, deprecated, default) and the checked field values when available.
218
+
219
+ ### `config.describe`
220
+
221
+ Describe all fields in the schema — paths, types, defaults, env bindings, secret markers, deprecation messages.
222
+
223
+ ### `config.init`
224
+
225
+ Generate example config files in TOML, JSON, JSONC, or YAML. Optionally writes `.env.example` and `.schema.json`.
226
+
227
+ Resolved deployment provenance remains available as the `deriveConfigProvenance()` library primitive. The Trails operator's `trails config explain` command has a narrower project-substrate contract: it explains source-static app identity and selection without treating `workspace.apps` as runtime config.
228
+
229
+ ## Testing
230
+
231
+ Trails that depend on `configResource` auto-resolve with a mock when registered in the topo:
232
+
233
+ ```typescript
234
+ import { testAll } from '@ontrails/testing';
235
+
236
+ const results = testAll(graph);
237
+ // configResource.mock() is called automatically
238
+ ```
239
+
240
+ For explicit test setup:
241
+
242
+ ```typescript
243
+ import { registerConfigState, clearConfigState } from '@ontrails/config';
244
+
245
+ afterEach(() => clearConfigState());
246
+
247
+ test('config trail', async () => {
248
+ registerConfigState({
249
+ resolved: { port: 3000 },
250
+ schema: z.object({ port: z.number() }),
251
+ });
252
+ // ...
253
+ });
254
+ ```
255
+
256
+ ## Installation
257
+
258
+ These commands target stable `0.2.0`. Run them after that version is published to npm.
259
+
260
+ ```bash
261
+ bun add --exact @ontrails/config@0.2.0 @ontrails/core@0.2.0 zod
262
+ ```
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@ontrails/config",
3
+ "version": "0.2.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/outfitter-dev/trails.git",
7
+ "directory": "packages/config"
8
+ },
9
+ "files": [
10
+ "src/**/*.ts",
11
+ "!src/**/__tests__/**",
12
+ "!src/**/*.test.ts",
13
+ "!src/**/*.test-d.ts",
14
+ "README.md",
15
+ "CHANGELOG.md"
16
+ ],
17
+ "type": "module",
18
+ "exports": {
19
+ ".": "./src/index.ts",
20
+ "./package.json": "./package.json"
21
+ },
22
+ "scripts": {
23
+ "build": "tsc -b",
24
+ "test": "bun test",
25
+ "typecheck": "tsc --noEmit",
26
+ "lint": "oxlint ./src",
27
+ "clean": "rm -rf dist *.tsbuildinfo"
28
+ },
29
+ "dependencies": {
30
+ "@ontrails/source": "^0.2.0",
31
+ "yaml": "^2.8.3"
32
+ },
33
+ "peerDependencies": {
34
+ "@ontrails/core": "^0.2.0",
35
+ "zod": "^4.3.5"
36
+ }
37
+ }