@ai-outfitter/outfitter 0.6.1 → 0.7.1
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/LICENSE.md +20 -50
- package/README.md +41 -280
- package/code/enterprise/LICENSE +35 -0
- package/code/enterprise/README.md +7 -0
- package/code/enterprise/cli/privateCatalogGate.cjs +134 -0
- package/code/enterprise/cli/privateCatalogSettings.cjs +59 -0
- package/code/enterprise/pi-extension/privateCatalogOnboarding.js +89 -0
- package/code/enterprise/private-catalog-boundary.json +9 -0
- package/code/enterprise/privateCatalog.js +24 -0
- package/code/enterprise/shared/privateCatalogPolicy.cjs +66 -0
- package/dist/agents/AdapterProfileControls.d.ts +2 -2
- package/dist/agents/AdapterProfileControls.js +8 -1
- package/dist/agents/AdapterProfileControls.js.map +1 -1
- package/dist/agents/AgentAdapter.d.ts +11 -0
- package/dist/agents/AgentLaunch.d.ts +6 -0
- package/dist/agents/AgentLaunch.js +89 -0
- package/dist/agents/AgentLaunch.js.map +1 -0
- package/dist/agents/claude/ClaudeAdapter.js +18 -3
- package/dist/agents/claude/ClaudeAdapter.js.map +1 -1
- package/dist/agents/pi/PiAdapter.js +162 -33
- package/dist/agents/pi/PiAdapter.js.map +1 -1
- package/dist/agents/pi/PiArgs.d.ts +2 -0
- package/dist/agents/pi/PiArgs.js +15 -0
- package/dist/agents/pi/PiArgs.js.map +1 -0
- package/dist/agents/pi/PiExtensionCache.d.ts +4 -0
- package/dist/agents/pi/PiExtensionCache.js +105 -0
- package/dist/agents/pi/PiExtensionCache.js.map +1 -0
- package/dist/cli/commands/PiLoginLaunch.d.ts +9 -2
- package/dist/cli/commands/PiLoginLaunch.js +817 -75
- package/dist/cli/commands/PiLoginLaunch.js.map +1 -1
- package/dist/cli/commands/RunCommand.d.ts +22 -3
- package/dist/cli/commands/RunCommand.js +104 -20
- package/dist/cli/commands/RunCommand.js.map +1 -1
- package/dist/cli/commands/SetupCommand.d.ts +19 -2
- package/dist/cli/commands/SetupCommand.js +281 -57
- package/dist/cli/commands/SetupCommand.js.map +1 -1
- package/dist/cli/commands/SyncCommand.d.ts +19 -1
- package/dist/cli/commands/SyncCommand.js +47 -6
- package/dist/cli/commands/SyncCommand.js.map +1 -1
- package/dist/cli/commands/WelcomeCommand.js +1 -1
- package/dist/cli/commands/WelcomeCommand.js.map +1 -1
- package/dist/cli/commands/assets/outfitter-ascii.txt +5 -0
- package/dist/cli/commands/profile/Command.d.ts +1 -0
- package/dist/cli/commands/profile/Command.js +3 -0
- package/dist/cli/commands/profile/Command.js.map +1 -1
- package/dist/cli/commands/profile/LintCommand.d.ts +19 -0
- package/dist/cli/commands/profile/LintCommand.js +123 -0
- package/dist/cli/commands/profile/LintCommand.js.map +1 -0
- package/dist/cli.js +8 -2
- package/dist/cli.js.map +1 -1
- package/dist/merge/ArrayMergePolicy.js.map +1 -1
- package/dist/merge/SettingsValueMerger.js.map +1 -1
- package/dist/profiles/Profile.d.ts +13 -1
- package/dist/profiles/Profile.js.map +1 -1
- package/dist/profiles/ProfileLoader.d.ts +4 -0
- package/dist/profiles/ProfileLoader.js +117 -17
- package/dist/profiles/ProfileLoader.js.map +1 -1
- package/dist/profiles/ProfileMerger.js +3 -0
- package/dist/profiles/ProfileMerger.js.map +1 -1
- package/dist/profiles/PromptIncludes.d.ts +32 -0
- package/dist/profiles/PromptIncludes.js +147 -0
- package/dist/profiles/PromptIncludes.js.map +1 -0
- package/dist/prompts/SystemPromptExport.d.ts +16 -0
- package/dist/prompts/SystemPromptExport.js +81 -0
- package/dist/prompts/SystemPromptExport.js.map +1 -0
- package/dist/schemas/profile.schema.json +37 -2
- package/dist/schemas/settings.schema.json +23 -0
- package/dist/settings/Settings.d.ts +9 -0
- package/dist/settings/Settings.js.map +1 -1
- package/dist/settings/SettingsLoader.js +5 -0
- package/dist/settings/SettingsLoader.js.map +1 -1
- package/dist/settings/SettingsMerger.js +11 -0
- package/dist/settings/SettingsMerger.js.map +1 -1
- package/package.json +7 -11
- package/src/schemas/profile.schema.json +37 -2
- package/src/schemas/settings.schema.json +23 -0
- package/doc/.deepreview +0 -30
- package/doc/architecture.md +0 -856
- package/doc/controllable-elements.md +0 -162
- package/doc/file_structure.md +0 -141
- package/doc/integration_test_system.md +0 -214
- package/doc/specs/validating_requirements_with_rules.md +0 -55
- package/doc/state_writeback_strategy.md +0 -342
- package/requirements/OFTR-001-project-foundation.md +0 -53
- package/requirements/OFTR-002-settings.md +0 -65
- package/requirements/OFTR-003-profiles.md +0 -60
- package/requirements/OFTR-004-sync-and-setup.md +0 -67
- package/requirements/OFTR-005-run-and-composite-profile.md +0 -60
- package/requirements/OFTR-006-agent-adapters.md +0 -66
- package/requirements/OFTR-007-controllable-elements.md +0 -32
- package/requirements/OFTR-008-requirements-governance.md +0 -42
- package/requirements/OFTR-009-release-publishing.md +0 -35
- package/requirements/OFTR-010-onboarding-welcome.md +0 -48
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
# State Writeback Strategy
|
|
2
|
-
|
|
3
|
-
This document describes Outfitter's current model for handling writes that agent CLIs make inside a composite profile.
|
|
4
|
-
|
|
5
|
-
A composite profile is temporary, but agent CLIs sometimes perform intentionally durable writes, such as logging in, installing plugins, changing settings, or updating MCP configuration.
|
|
6
|
-
Outfitter makes those paths explicit: adapter-declared writable paths are materialized with a resolved `state_persistence` strategy before the child CLI starts, and non-persistent or unknown writes are diagnosed after the child exits.
|
|
7
|
-
|
|
8
|
-
## Functional model
|
|
9
|
-
|
|
10
|
-
Outfitter separates three kinds of files that may exist in a composite profile:
|
|
11
|
-
|
|
12
|
-
1. **Generated runtime files**: files Outfitter assembles from settings, profiles, templates, and adapter rules.
|
|
13
|
-
Outfitter may regenerate these while the child agent is running when their source inputs change.
|
|
14
|
-
2. **Declared state paths**: adapter-known files or directories the agent CLI may update intentionally, such as auth, settings, MCP config, plugins, caches, and sessions.
|
|
15
|
-
3. **Unknown writes**: files or directories the agent creates outside the adapter-declared state paths.
|
|
16
|
-
|
|
17
|
-
Only declared state paths can be made durable automatically.
|
|
18
|
-
Unknown writes are never silently persisted because Outfitter does not know their intended owner, merge rules, or durable destination.
|
|
19
|
-
Generated runtime files and declared state paths are deliberately handled separately so live profile/template updates do not erase or re-baseline agent state changes made during the same run.
|
|
20
|
-
|
|
21
|
-
The user-facing state update lifecycle is:
|
|
22
|
-
|
|
23
|
-
1. **Choose a profile**.
|
|
24
|
-
Profile resolution determines the effective `state_persistence` map using normal profile precedence.
|
|
25
|
-
2. **Resolve adapter defaults**.
|
|
26
|
-
For each path the selected adapter declares, Outfitter uses the profile override when present and otherwise uses the adapter default.
|
|
27
|
-
3. **Prepare the composite profile**.
|
|
28
|
-
Durable paths are connected to a profile-managed or native CLI location; non-durable paths are created as normal temporary composite profile paths.
|
|
29
|
-
4. **Run the agent**.
|
|
30
|
-
The agent CLI reads and writes the composite profile as if it were its normal configuration directory.
|
|
31
|
-
5. **Classify changes after exit**.
|
|
32
|
-
Outfitter checks non-durable declared paths and unknown paths and reports or fails according to their strategies.
|
|
33
|
-
6. **Clean up temporary state**.
|
|
34
|
-
Temporary composite profile contents are discarded; durable symlink targets remain in their profile or native CLI location.
|
|
35
|
-
|
|
36
|
-
## Current behavior
|
|
37
|
-
|
|
38
|
-
- Composite profiles remain temporary and reproducible by default.
|
|
39
|
-
- Outfitter does not do generic post-run copy-back or JSON/YAML merge-back.
|
|
40
|
-
- Persistent state is represented by symlinking a composite profile path to a profile file/directory or to the native CLI fallback path.
|
|
41
|
-
- Adapters may generate a concrete runtime file for a declared state path when they need deterministic launch-time reconciliation.
|
|
42
|
-
For example, the Pi adapter can generate a transformed `settings.json` that removes native `packages` entries already supplied by profile-controlled extensions, and then mark that declared path as `discard` for write detection during the run.
|
|
43
|
-
- Every adapter-declared state path has a resolved strategy before launch: profile overrides win, otherwise the adapter `default_strategy` is used, except for adapter-generated reconciliation files that are intentionally treated as discarded runtime files.
|
|
44
|
-
- Invalid or disallowed profile-requested `state_persistence` strategies fail before launch; adapter-internal reconciliation may still choose a one-run handling strategy for a generated runtime file.
|
|
45
|
-
- Non-persistent `warn` and `error` strategies are checked after the child CLI exits.
|
|
46
|
-
- Unknown writes outside adapter-declared paths are checked with the adapter's `unknown` pseudo-path strategy.
|
|
47
|
-
- `prompt` is reserved for a future interactive/control-plane workflow.
|
|
48
|
-
When accepted by a declaration today, it is treated as a non-persistent diagnostic like `warn`.
|
|
49
|
-
|
|
50
|
-
## Non-goals
|
|
51
|
-
|
|
52
|
-
- Outfitter does not implement generic copy-back from the composite profile to profiles.
|
|
53
|
-
- Outfitter does not implement generic structured merge-back.
|
|
54
|
-
- Outfitter does not silently persist unknown writes.
|
|
55
|
-
|
|
56
|
-
## Profile stack and native fallback
|
|
57
|
-
|
|
58
|
-
State persistence is a normal profile setting.
|
|
59
|
-
Its strategy overrides resolve through the same profile stack as other profile data:
|
|
60
|
-
|
|
61
|
-
```text
|
|
62
|
-
project-local profile
|
|
63
|
-
project profile
|
|
64
|
-
user profile
|
|
65
|
-
URI/cache profiles
|
|
66
|
-
explicit inheritance
|
|
67
|
-
implicit user default profile
|
|
68
|
-
Outfitter default profile
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Native CLI state is not represented as an extra profile layer.
|
|
72
|
-
For `symlink` paths without a profile-provided source, the selected adapter resolves a native fallback location directly, such as `~/.pi/agent/...` for most Pi state paths, `~/.claude/...` for most Claude Code state paths, or `<cache_directory>/utilities` for Pi `utilities/` and `bin/`.
|
|
73
|
-
This native fallback is not a base profile: it does not participate in profile inheritance or merge precedence, and it cannot contribute controls or profile YAML.
|
|
74
|
-
Claude Code `projects/` is additionally controlled by `controls.session_directory` or `controls.claude.session_directory` when set.
|
|
75
|
-
|
|
76
|
-
## Path-keyed adapter declarations
|
|
77
|
-
|
|
78
|
-
Adapters declare writable state paths directly, using relative file paths as keys.
|
|
79
|
-
Directory paths use a trailing slash.
|
|
80
|
-
The same key is used for adapter coverage, `state_persistence` overrides, profile resource lookup, native fallback lookup, and composite profile materialization.
|
|
81
|
-
|
|
82
|
-
The Pi adapter currently declares:
|
|
83
|
-
|
|
84
|
-
```yaml
|
|
85
|
-
state_paths:
|
|
86
|
-
auth.json:
|
|
87
|
-
default_strategy: symlink
|
|
88
|
-
allowed_strategies: [symlink, error, prompt]
|
|
89
|
-
|
|
90
|
-
settings.json:
|
|
91
|
-
default_strategy: symlink
|
|
92
|
-
allowed_strategies: [symlink, warn, error, prompt]
|
|
93
|
-
note: >-
|
|
94
|
-
When profile-controlled Pi extensions duplicate native settings packages,
|
|
95
|
-
Outfitter may generate a transformed runtime settings.json and treat this
|
|
96
|
-
declared path as discard for that launch. That discard handling is
|
|
97
|
-
adapter-internal; users still cannot request settings.json: discard
|
|
98
|
-
because discard is not listed in allowed_strategies.
|
|
99
|
-
|
|
100
|
-
mcp.json:
|
|
101
|
-
default_strategy: symlink
|
|
102
|
-
allowed_strategies: [symlink, warn, error, prompt]
|
|
103
|
-
|
|
104
|
-
models.json:
|
|
105
|
-
default_strategy: symlink
|
|
106
|
-
allowed_strategies: [symlink, warn, error, prompt]
|
|
107
|
-
|
|
108
|
-
trust.json:
|
|
109
|
-
default_strategy: symlink
|
|
110
|
-
allowed_strategies: [symlink, warn, error, prompt]
|
|
111
|
-
|
|
112
|
-
plugins/:
|
|
113
|
-
default_strategy: symlink
|
|
114
|
-
allowed_strategies: [symlink, discard, warn, error, prompt]
|
|
115
|
-
|
|
116
|
-
cache/:
|
|
117
|
-
default_strategy: symlink
|
|
118
|
-
allowed_strategies: [symlink, discard, warn, error]
|
|
119
|
-
|
|
120
|
-
sessions/:
|
|
121
|
-
default_strategy: symlink
|
|
122
|
-
allowed_strategies: [symlink, discard, warn, error]
|
|
123
|
-
|
|
124
|
-
npm/:
|
|
125
|
-
default_strategy: symlink
|
|
126
|
-
allowed_strategies: [symlink, discard, warn, error]
|
|
127
|
-
|
|
128
|
-
git/:
|
|
129
|
-
default_strategy: symlink
|
|
130
|
-
allowed_strategies: [symlink, discard, warn, error]
|
|
131
|
-
|
|
132
|
-
tmp/:
|
|
133
|
-
default_strategy: symlink
|
|
134
|
-
allowed_strategies: [symlink, discard]
|
|
135
|
-
|
|
136
|
-
utilities/:
|
|
137
|
-
default_strategy: symlink
|
|
138
|
-
allowed_strategies: [symlink, discard, warn, error]
|
|
139
|
-
|
|
140
|
-
bin/:
|
|
141
|
-
default_strategy: symlink
|
|
142
|
-
allowed_strategies: [symlink, discard, warn, error]
|
|
143
|
-
|
|
144
|
-
unknown:
|
|
145
|
-
default_strategy: warn
|
|
146
|
-
allowed_strategies: [discard, warn, error, prompt]
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
The Claude Code adapter currently declares:
|
|
150
|
-
|
|
151
|
-
```yaml
|
|
152
|
-
state_paths:
|
|
153
|
-
settings.json:
|
|
154
|
-
default_strategy: symlink
|
|
155
|
-
allowed_strategies: [symlink, warn, error, prompt]
|
|
156
|
-
|
|
157
|
-
agents/:
|
|
158
|
-
default_strategy: symlink
|
|
159
|
-
allowed_strategies: [symlink, discard, warn, error, prompt]
|
|
160
|
-
|
|
161
|
-
skills/:
|
|
162
|
-
default_strategy: symlink
|
|
163
|
-
allowed_strategies: [symlink, discard, warn, error, prompt]
|
|
164
|
-
|
|
165
|
-
commands/:
|
|
166
|
-
default_strategy: symlink
|
|
167
|
-
allowed_strategies: [symlink, discard, warn, error, prompt]
|
|
168
|
-
|
|
169
|
-
plugins/:
|
|
170
|
-
default_strategy: symlink
|
|
171
|
-
allowed_strategies: [symlink, discard, warn, error, prompt]
|
|
172
|
-
|
|
173
|
-
projects/:
|
|
174
|
-
default_strategy: symlink
|
|
175
|
-
allowed_strategies: [symlink, discard, warn, error]
|
|
176
|
-
|
|
177
|
-
debug/:
|
|
178
|
-
default_strategy: symlink
|
|
179
|
-
allowed_strategies: [symlink, discard, warn, error]
|
|
180
|
-
|
|
181
|
-
unknown:
|
|
182
|
-
default_strategy: warn
|
|
183
|
-
allowed_strategies: [discard, warn, error, prompt]
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
## Profile layout for state files
|
|
187
|
-
|
|
188
|
-
State files live under the relevant CLI-specific profile folder:
|
|
189
|
-
|
|
190
|
-
```text
|
|
191
|
-
profiles/
|
|
192
|
-
default/
|
|
193
|
-
profile.yml
|
|
194
|
-
cli_specific/
|
|
195
|
-
pi/
|
|
196
|
-
auth.json
|
|
197
|
-
settings.json
|
|
198
|
-
plugins/
|
|
199
|
-
claude/
|
|
200
|
-
settings.json
|
|
201
|
-
skills/
|
|
202
|
-
commands/
|
|
203
|
-
plugins/
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
Except for special adapter paths described below, when a selected strategy is `symlink`, Outfitter searches the resolved profile folders from highest to lowest precedence for `cli_specific/<adapter>/<state-path>`.
|
|
207
|
-
If a profile contains the file or directory, Outfitter symlinks the composite profile path to that source.
|
|
208
|
-
|
|
209
|
-
For most Pi paths, if no profile source exists, Outfitter falls back to the corresponding native Pi agent path under `~/.pi/agent`.
|
|
210
|
-
Missing native fallback files/directories are created so the composite profile symlink has a durable destination.
|
|
211
|
-
|
|
212
|
-
Pi `utilities/` and `bin/` are special cache-backed paths: both resolve to `<cache_directory>/utilities` instead of profile or native Pi state.
|
|
213
|
-
This keeps pi-managed helper binaries reusable across temporary composite profiles without treating them as user-editable profile files.
|
|
214
|
-
|
|
215
|
-
For most Claude Code paths, if no profile source exists, Outfitter falls back to the corresponding native Claude Code path under `~/.claude`.
|
|
216
|
-
Claude Code `projects/` is special: `controls.claude.session_directory` overrides generic `controls.session_directory`, and the selected session directory becomes the `projects/` symlink source.
|
|
217
|
-
If neither session-directory control is present, `projects/` falls back to `~/.claude/projects`.
|
|
218
|
-
|
|
219
|
-
## `state_persistence`
|
|
220
|
-
|
|
221
|
-
Profiles may override persistence by mapping adapter-declared paths to strategy names:
|
|
222
|
-
|
|
223
|
-
```yaml
|
|
224
|
-
state_persistence:
|
|
225
|
-
auth.json: symlink
|
|
226
|
-
settings.json: symlink
|
|
227
|
-
plugins/: symlink
|
|
228
|
-
cache/: discard
|
|
229
|
-
sessions/: discard
|
|
230
|
-
unknown: warn
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
The values are concrete strategy names.
|
|
234
|
-
`state_persistence` only needs overrides; omitted paths use the adapter declaration's `default_strategy`.
|
|
235
|
-
|
|
236
|
-
`state_persistence` is validated by the profile JSON Schema at read boundaries.
|
|
237
|
-
Outfitter also validates the resolved strategy against the adapter declaration before launch.
|
|
238
|
-
|
|
239
|
-
Functional examples:
|
|
240
|
-
|
|
241
|
-
```yaml
|
|
242
|
-
# Persist logins and settings, but make caches and sessions run-local.
|
|
243
|
-
state_persistence:
|
|
244
|
-
auth.json: symlink
|
|
245
|
-
settings.json: symlink
|
|
246
|
-
cache/: discard
|
|
247
|
-
sessions/: discard
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
```yaml
|
|
251
|
-
# CI profile: fail if pi changes settings, MCP config, or unknown files.
|
|
252
|
-
state_persistence:
|
|
253
|
-
settings.json: error
|
|
254
|
-
mcp.json: error
|
|
255
|
-
plugins/: error
|
|
256
|
-
unknown: error
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
```yaml
|
|
260
|
-
# Exploratory profile: allow plugin experiments but report them after exit.
|
|
261
|
-
state_persistence:
|
|
262
|
-
plugins/: warn
|
|
263
|
-
unknown: warn
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## Composite profile materialization
|
|
267
|
-
|
|
268
|
-
Before launch, Outfitter processes each adapter-declared state path:
|
|
269
|
-
|
|
270
|
-
1. Resolve the path's strategy from profile `state_persistence` overrides, then the adapter `default_strategy`.
|
|
271
|
-
2. Validate that the strategy is allowed for that path.
|
|
272
|
-
3. Resolve a source path through the profile hierarchy when the strategy is `symlink`.
|
|
273
|
-
4. Materialize the composite profile path.
|
|
274
|
-
5. Record a baseline fingerprint for non-persistent and unknown write detection.
|
|
275
|
-
|
|
276
|
-
For `symlink`, Outfitter creates a symlink from the composite profile path to the resolved profile or native CLI source.
|
|
277
|
-
|
|
278
|
-
For `discard`, `warn`, `error`, and `prompt`, Outfitter creates normal temporary composite profile paths where needed and observes whether they changed.
|
|
279
|
-
|
|
280
|
-
## Unknown writes
|
|
281
|
-
|
|
282
|
-
The `unknown` pseudo-path controls writes outside adapter-declared paths:
|
|
283
|
-
|
|
284
|
-
```yaml
|
|
285
|
-
state_persistence:
|
|
286
|
-
unknown: warn
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
Supported `unknown` strategies are non-persistent only:
|
|
290
|
-
|
|
291
|
-
- `discard`
|
|
292
|
-
- `warn`
|
|
293
|
-
- `error`
|
|
294
|
-
- `prompt`
|
|
295
|
-
|
|
296
|
-
`unknown` does not support `symlink`, because there is no declared durable destination.
|
|
297
|
-
|
|
298
|
-
## Strategy selection guide
|
|
299
|
-
|
|
300
|
-
Use `symlink` when a write is part of durable agent setup, such as logging in, editing native settings, updating MCP config, or installing plugins that should be reused.
|
|
301
|
-
Use `discard` when the data is useful only during the current run, such as cache entries or throwaway sessions.
|
|
302
|
-
Use `warn` when mutation is acceptable but should be visible to the user.
|
|
303
|
-
Use `error` when mutation means the run was not reproducible enough, especially in CI or locked-down project profiles.
|
|
304
|
-
Use `prompt` only as a forward-compatible declaration for future interactive handling.
|
|
305
|
-
|
|
306
|
-
## Strategies
|
|
307
|
-
|
|
308
|
-
### `symlink`
|
|
309
|
-
|
|
310
|
-
Outfitter resolves the state path through the profile hierarchy, then the native CLI fallback, and symlinks that source into the composite profile.
|
|
311
|
-
Persistence happens because the CLI writes through the symlink to an intentional file or directory.
|
|
312
|
-
|
|
313
|
-
### `discard`
|
|
314
|
-
|
|
315
|
-
Writes are allowed in the composite profile and are thrown away when the composite profile is deleted.
|
|
316
|
-
Outfitter does not emit diagnostics for changed `discard` paths.
|
|
317
|
-
|
|
318
|
-
### `warn`
|
|
319
|
-
|
|
320
|
-
Writes are allowed, discarded, and reported after the child exits.
|
|
321
|
-
`--strict` makes these warnings fatal.
|
|
322
|
-
|
|
323
|
-
### `error`
|
|
324
|
-
|
|
325
|
-
Writes are allowed during the child process but cause Outfitter to fail after the child exits if the path changed.
|
|
326
|
-
This is useful for CI and strict reproducibility.
|
|
327
|
-
|
|
328
|
-
### `prompt`
|
|
329
|
-
|
|
330
|
-
`prompt` is reserved for a future interactive/control-plane workflow.
|
|
331
|
-
Current implementations that allow it treat writes as non-persistent diagnostics, equivalent to `warn`, with the strategy name preserved in the message.
|
|
332
|
-
|
|
333
|
-
## Rationale
|
|
334
|
-
|
|
335
|
-
Path-keyed state declarations keep the model simple:
|
|
336
|
-
|
|
337
|
-
- the adapter declares the paths it knows the CLI may write and their default strategies;
|
|
338
|
-
- profiles may provide files at those same paths;
|
|
339
|
-
- the native fallback exposes native CLI files at those same paths;
|
|
340
|
-
- `state_persistence` says what to do with each path.
|
|
341
|
-
|
|
342
|
-
This avoids ambiguous writeback behavior and gives users a clear rule: if a CLI write should persist, configure that composite profile path as `symlink` and provide or accept the profile/native file that should receive the mutation.
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# OFTR-001: Project Foundation
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Outfitter is a TypeScript CLI project.
|
|
6
|
-
This document specifies the baseline runtime, language, test, lint, and documentation conventions that must exist before feature work grows.
|
|
7
|
-
|
|
8
|
-
## Requirements
|
|
9
|
-
|
|
10
|
-
### OFTR-001.1: Runtime, Package Manager, and Language
|
|
11
|
-
|
|
12
|
-
1. The project MUST use TypeScript as its primary implementation language.
|
|
13
|
-
2. The project MUST declare Node.js `>=22.19.0` as the supported runtime baseline for the first version.
|
|
14
|
-
3. TypeScript configuration MUST enable strict type checking.
|
|
15
|
-
4. The project MUST provide a separate build TypeScript configuration that emits production files from `src/` to `dist/`.
|
|
16
|
-
5. The project MUST use npm as its package manager for the first version.
|
|
17
|
-
6. The project MUST commit `package-lock.json` after dependency installation or updates.
|
|
18
|
-
7. When an implementation library choice remains unclear, the project SHOULD prefer the same library or convention used by pi.dev.
|
|
19
|
-
|
|
20
|
-
### OFTR-001.2: Test Framework and Coverage
|
|
21
|
-
|
|
22
|
-
1. The project MUST use Vitest as its test framework before implementing substantial runtime behavior.
|
|
23
|
-
2. The test command MUST be runnable from package scripts.
|
|
24
|
-
3. The coverage command MUST use `@vitest/coverage-v8`.
|
|
25
|
-
4. The test configuration MUST enforce at least 99% global coverage for statements, branches, functions, and lines.
|
|
26
|
-
5. The coverage configuration MUST include all `src/**/*.ts` files even when a source file is not imported by any test.
|
|
27
|
-
6. Tests that validate formal requirements MUST follow the traceability format required by OFTR-008.3.
|
|
28
|
-
|
|
29
|
-
### OFTR-001.3: Linting and Complexity
|
|
30
|
-
|
|
31
|
-
1. The project MUST configure ESLint with TypeScript support using `eslint`, `@eslint/js`, and `typescript-eslint`.
|
|
32
|
-
2. ESLint MUST enforce a maximum cyclomatic complexity of 10.
|
|
33
|
-
3. The lint command MUST be runnable from package scripts.
|
|
34
|
-
4. Production code SHOULD use small command objects and services so the complexity limit remains practical.
|
|
35
|
-
|
|
36
|
-
### OFTR-001.4: Persisted File Format Policy
|
|
37
|
-
|
|
38
|
-
1. User-editable persisted Outfitter configuration MUST use YAML instead of JSON unless the file is a JSON Schema.
|
|
39
|
-
2. Every user-editable YAML file format that Outfitter reads MUST have a corresponding JSON Schema.
|
|
40
|
-
3. Outfitter MUST validate YAML files against their JSON Schemas anywhere those files are read.
|
|
41
|
-
4. JSON Schema files MAY use JSON because schemas are tooling-facing validation artifacts.
|
|
42
|
-
|
|
43
|
-
### OFTR-001.5: Initial Dependency Set
|
|
44
|
-
|
|
45
|
-
1. The project MUST use Commander as the CLI framework.
|
|
46
|
-
2. The project MUST use `yaml` for YAML parsing and serialization.
|
|
47
|
-
3. The project MUST use AJV for runtime JSON Schema validation.
|
|
48
|
-
4. The project SHOULD use TypeBox when TypeScript-friendly schema authoring is useful.
|
|
49
|
-
5. The project MUST use `defu` for controlled settings and profile deep merging unless a documented merge-specific reason requires custom code.
|
|
50
|
-
6. The project MUST use `cross-spawn` for launching inner agent CLI processes.
|
|
51
|
-
7. The project SHOULD use `glob` for profile and resource discovery.
|
|
52
|
-
8. The project SHOULD use `hosted-git-info` for hosted git URI parsing when the URI format is supported by that library.
|
|
53
|
-
9. The project MAY use `chalk` for terminal diagnostics.
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# OFTR-002: Settings Discovery and Validation
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Outfitter settings are the merged result of user, project, and project-local `.outfitter/settings.yml` files.
|
|
6
|
-
The internal Settings object is the single source of resolved configuration for commands.
|
|
7
|
-
|
|
8
|
-
## Requirements
|
|
9
|
-
|
|
10
|
-
### OFTR-002.1: Settings Locations
|
|
11
|
-
|
|
12
|
-
1. Outfitter MUST support a user settings file at `~/.outfitter/settings.yml`.
|
|
13
|
-
2. Outfitter MUST support a project settings file at `<project>/.outfitter/settings.yml`.
|
|
14
|
-
3. Outfitter MUST support a project-local settings file at `<project>/.outfitter/local/settings.yml`.
|
|
15
|
-
4. Outfitter MUST collectively refer to discovered settings files as `settings.yml` in user-facing documentation when discussing the merged settings concept.
|
|
16
|
-
|
|
17
|
-
### OFTR-002.2: Settings Precedence
|
|
18
|
-
|
|
19
|
-
1. Project-local settings MUST take precedence over project settings.
|
|
20
|
-
2. Project settings MUST take precedence over user settings.
|
|
21
|
-
3. User settings MUST take precedence over built-in defaults.
|
|
22
|
-
4. Outfitter MUST expose the merged result as a conceptual internal `Settings` object.
|
|
23
|
-
5. The Settings loader SHOULD be designed so future settings sources can be added without changing command implementations.
|
|
24
|
-
|
|
25
|
-
### OFTR-002.3: Settings Schema
|
|
26
|
-
|
|
27
|
-
1. Outfitter MUST provide a JSON Schema for `settings.yml`.
|
|
28
|
-
2. Outfitter MUST validate every discovered `settings.yml` file against the settings JSON Schema before merging it.
|
|
29
|
-
3. Validation diagnostics MUST identify the file that failed validation.
|
|
30
|
-
4. Validation diagnostics SHOULD identify the failing setting path when the validator provides that information.
|
|
31
|
-
|
|
32
|
-
### OFTR-002.4: Default Profile
|
|
33
|
-
|
|
34
|
-
1. The user settings file `~/.outfitter/settings.yml` MUST declare a default profile after `outfitter setup` completes.
|
|
35
|
-
2. `outfitter run` MUST use the resolved default profile when no profile is selected with `-p` or `--profile`.
|
|
36
|
-
3. Outfitter MUST report an actionable error when no selected profile and no default profile are available.
|
|
37
|
-
|
|
38
|
-
### OFTR-002.5: Profile Sources in Settings
|
|
39
|
-
|
|
40
|
-
1. `settings.yml` MAY contain a `profile_sources` array.
|
|
41
|
-
2. Each `profile_sources` entry MUST specify either a local `path`, a remote `uri`, or a `github` shorthand.
|
|
42
|
-
3. A local-only `path` profile source MUST resolve relative to the settings file containing it when the path is relative.
|
|
43
|
-
4. A local-only `path` profile source MUST point to a folder containing profile folders rather than to one specific profile folder.
|
|
44
|
-
5. A `uri` or `github` profile source MUST be syncable by `outfitter sync`.
|
|
45
|
-
6. A `uri` or `github` profile source MAY specify `ref` to select a branch, tag, or commit.
|
|
46
|
-
7. A `uri` or `github` profile source MAY specify `path` to load profiles from a repository subdirectory.
|
|
47
|
-
8. A profile source MAY specify `only` to allow only named profiles from that source.
|
|
48
|
-
9. A profile source MAY specify `except` to exclude named profiles from that source.
|
|
49
|
-
10. If neither `only` nor `except` is specified, Outfitter MUST load all profiles from the source.
|
|
50
|
-
|
|
51
|
-
### OFTR-002.6: Remote Settings Sources
|
|
52
|
-
|
|
53
|
-
1. `settings.yml` MAY contain a `remote_settings` array.
|
|
54
|
-
2. Each `remote_settings` entry MUST specify either a remote `uri` or a `github` shorthand.
|
|
55
|
-
3. Each `remote_settings` entry MUST specify `path` to a settings-style YAML file inside the remote repository.
|
|
56
|
-
4. A `remote_settings` entry MAY specify `ref` to select a branch, tag, or commit.
|
|
57
|
-
5. Outfitter MUST load cached remote settings files from their repository subpaths when resolving settings.
|
|
58
|
-
6. Local discovered settings MUST take precedence over remote settings when both define the same setting.
|
|
59
|
-
|
|
60
|
-
### OFTR-002.7: Cache Directory Setting
|
|
61
|
-
|
|
62
|
-
1. `settings.yml` MAY contain a `cache_directory` path.
|
|
63
|
-
2. Relative `cache_directory` values MUST resolve relative to the settings file containing them.
|
|
64
|
-
3. When `cache_directory` is not configured, Outfitter MUST use `~/.outfitter/cache` as the default cache directory.
|
|
65
|
-
4. Agent adapters MUST receive the resolved cache directory when assembling a composite profile so persistent composite profile links use the configured cache location.
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# OFTR-003: Profiles and Inheritance
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Profiles describe reusable agent-CLI loadouts.
|
|
6
|
-
Outfitter resolves profile definitions across settings scopes, explicit sources, inherited profiles, and the implicit user default profile.
|
|
7
|
-
|
|
8
|
-
## Requirements
|
|
9
|
-
|
|
10
|
-
### OFTR-003.1: Profile Folder Layout
|
|
11
|
-
|
|
12
|
-
1. A profile MUST be represented by a folder with a required `profile.yml` file.
|
|
13
|
-
2. Outfitter MUST provide a JSON Schema for `profile.yml`.
|
|
14
|
-
3. Outfitter MUST validate every loaded `profile.yml` file against the profile JSON Schema.
|
|
15
|
-
4. A profile folder MAY contain conventional resource folders such as `skills`, `prompts`, `extensions`, and `deepwork/jobs`.
|
|
16
|
-
5. A profile folder MAY contain `cli_specific/<cli-name>/` folders for agent-specific resources and overrides.
|
|
17
|
-
|
|
18
|
-
### OFTR-003.2: Profile Identity
|
|
19
|
-
|
|
20
|
-
1. Profile IDs MUST be stable identifiers suitable for commands, logs, cache keys, and documentation.
|
|
21
|
-
2. Profile IDs MUST match the regex `^[a-z0-9][a-z0-9._-]*[a-z0-9]$|^[a-z0-9]$`.
|
|
22
|
-
3. Outfitter MUST reject profile IDs that cannot be safely referenced from the CLI.
|
|
23
|
-
4. Outfitter SHOULD support a separate display label if human-readable names need spaces or punctuation.
|
|
24
|
-
5. Profiles MAY include a short `description` for interactive prompts and profile discovery surfaces.
|
|
25
|
-
|
|
26
|
-
### OFTR-003.3: Profile Scope Precedence
|
|
27
|
-
|
|
28
|
-
1. Project-local profile definitions MUST take precedence over project profile definitions for the same profile name.
|
|
29
|
-
2. Project profile definitions MUST take precedence over user profile definitions for the same profile name.
|
|
30
|
-
3. User profile definitions MUST take precedence over cached URI profile definitions for the same profile name.
|
|
31
|
-
4. Cached URI profile definitions MUST be considered according to resolved source order when multiple URI sources provide the same profile name.
|
|
32
|
-
|
|
33
|
-
### OFTR-003.4: Profile Inheritance
|
|
34
|
-
|
|
35
|
-
1. `profile.yml` MAY specify an ordered `inherits` array of profile names.
|
|
36
|
-
2. Inherited profiles MUST be treated as lower-precedence sources for the inheriting profile.
|
|
37
|
-
3. Outfitter MUST recursively resolve inherited profiles.
|
|
38
|
-
4. Outfitter MUST detect inheritance cycles and report them as validation errors.
|
|
39
|
-
5. Outfitter MUST preserve inherited profile order when building the profile stack.
|
|
40
|
-
|
|
41
|
-
### OFTR-003.5: Default Profile Selection
|
|
42
|
-
|
|
43
|
-
1. Outfitter MUST use the configured `default_profile` only when no explicit profile is selected.
|
|
44
|
-
2. When an explicit profile is selected, Outfitter MUST resolve only that profile and its declared `inherits` chain.
|
|
45
|
-
3. Outfitter MUST NOT include the configured `default_profile` as an implicit base layer for an explicit profile.
|
|
46
|
-
|
|
47
|
-
### OFTR-003.6: Profile Merging
|
|
48
|
-
|
|
49
|
-
1. Outfitter MUST merge resolved profile layers deterministically.
|
|
50
|
-
2. YAML object values SHOULD be merged with `defu` or an equivalent controlled deep-merge utility.
|
|
51
|
-
3. Array merge behavior MUST be documented per profile key before that key is treated as stable.
|
|
52
|
-
4. CLI-specific profile content MUST take precedence over generic controls when both generate the same agent-specific artifact.
|
|
53
|
-
5. Outfitter MUST compose `append_system_prompt` values from multiple resolved profile layers into repeated agent append-prompt inputs without requiring profiles to use raw CLI `args` for prompt composition.
|
|
54
|
-
|
|
55
|
-
### OFTR-003.7: Template Profiles
|
|
56
|
-
|
|
57
|
-
1. A profile MAY set top-level `template: true` to indicate it is intended for inheritance by runnable profiles rather than direct launch.
|
|
58
|
-
2. Outfitter MUST allow template profiles to contribute controls through `inherits` without marking the inheriting profile as a template.
|
|
59
|
-
3. Outfitter MUST reject direct launches of template profiles, including launches selected through `default_profile`.
|
|
60
|
-
4. `outfitter profile list` SHOULD hide template profiles by default and MUST expose them when the user explicitly requests all profiles.
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# OFTR-004: Setup, Sync, and Profile Creation Commands
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Outfitter provides setup and maintenance commands that create initial configuration, synchronize remote profile sources, and generate placeholder profile folders.
|
|
6
|
-
|
|
7
|
-
## Requirements
|
|
8
|
-
|
|
9
|
-
### OFTR-004.1: Setup Command
|
|
10
|
-
|
|
11
|
-
1. Outfitter MUST provide a `setup` command.
|
|
12
|
-
2. The `setup` command MUST create `~/.outfitter/settings.yml` when it does not exist.
|
|
13
|
-
3. The `setup` command MUST create a default user profile when no user default profile exists.
|
|
14
|
-
4. The `setup` command MUST validate discovered settings files.
|
|
15
|
-
5. The `setup` command MUST run sync behavior for URI-based profile sources.
|
|
16
|
-
6. The `setup` command SHOULD avoid overwriting existing user files unless a future explicit force option authorizes replacement.
|
|
17
|
-
7. When provided a setup source URI, the `setup` command MUST use that source repository's Outfitter `settings.yml` and profiles as the initial setup starting point for the selected import target.
|
|
18
|
-
8. The interactive `setup` command MUST require interactive TTY streams on both stdin and stdout before prompting.
|
|
19
|
-
9. The interactive `setup` command MUST synchronize remote profile sources before any setup profile choice prompt.
|
|
20
|
-
10. Initial interactive first-run setup MUST NOT ask a separate default-profile choice before welcome onboarding; the welcome role selection determines the generated local default profile.
|
|
21
|
-
11. When the interactive `setup` command presents setup profile choices outside the initial welcome handoff, it MUST present discovered profile IDs as default-profile choices and preserve available display labels in the prompt choices.
|
|
22
|
-
12. When the interactive `setup` command presents setup profile choices outside the initial welcome handoff, it MUST validate the selected default profile ID before writing it to `settings.yml`.
|
|
23
|
-
13. After the interactive `setup` command writes a selected default profile, any newly-created fallback default profile file MUST correspond to the final selected default profile.
|
|
24
|
-
14. When interactive `setup <source>` presents setup profile choices, it MUST limit those choices to profiles from the passed setup source and MUST NOT include default profile sources from pre-existing effective settings.
|
|
25
|
-
15. When interactive `setup <source>` presents setup profile choices and the setup source declares an explicit `default_profile` that exists among those source choices, it MUST make that profile the prompt default and first displayed choice; pre-existing user defaults MUST NOT override that source default for the setup-source prompt.
|
|
26
|
-
16. Interactive `setup <source>` MUST NOT present a default-profile choice before the setup-source welcome/import explanation.
|
|
27
|
-
17. Interactive `setup <source>` MUST explain which setup source is being imported and MUST let the user choose whether to install profiles into user home or the current project before writing setup-source profiles/settings.
|
|
28
|
-
18. Interactive `setup <source>` MUST present exactly one setup-source profile/default choice after the import target choice when setup-source profiles are available.
|
|
29
|
-
19. When the interactive setup-source import target is user home, setup MUST copy missing source profiles into `~/.outfitter/profiles`, write the selected default profile to `~/.outfitter/settings.yml`, and preserve non-overwrite copy behavior.
|
|
30
|
-
20. When the interactive setup-source import target is the current project, setup MUST copy missing source profiles into `<project>/.outfitter/profiles`, write the selected default profile to `<project>/.outfitter/settings.yml`, ensure that project settings expose `./profiles`, and preserve any existing user default profile.
|
|
31
|
-
21. After interactive `setup <source>` imports the selected default profile, setup MUST offer to start Outfitter with that selected profile.
|
|
32
|
-
22. When the user declines the post-import start offer, setup MUST exit without launching and show both `outfitter` for starting the configured default profile and `outfitter --profile <selected-profile>` for starting it explicitly.
|
|
33
|
-
23. Non-interactive `setup <source>` completion MUST NOT launch Outfitter and MUST show the same default and explicit start command guidance.
|
|
34
|
-
|
|
35
|
-
### OFTR-004.2: Sync Command
|
|
36
|
-
|
|
37
|
-
1. Outfitter MUST provide a `sync` command.
|
|
38
|
-
2. The `sync` command MUST read and validate settings before synchronizing sources.
|
|
39
|
-
3. The `sync` command MUST fetch or update remote settings sources and URI-based profile sources.
|
|
40
|
-
4. The `sync` command MUST store plain URI-based profile sources without `ref` or repository subpaths under `~/.outfitter/cache/profiles/<encoded-uri>/`, and MUST store URI or GitHub sources with `ref` or repository subpaths under `~/.outfitter/cache/repos/<encoded-uri-and-ref>/`.
|
|
41
|
-
5. The encoded URI cache path MUST support non-GitHub URIs.
|
|
42
|
-
6. The `sync` command MUST validate profiles loaded from synchronized sources.
|
|
43
|
-
7. The `sync` command SHOULD report whether each source was updated, unchanged, skipped, or failed.
|
|
44
|
-
8. The first version of `sync` MUST NOT require lockfile-based profile source reproducibility.
|
|
45
|
-
9. The `sync` command MUST redact credentials embedded in source URIs from user-facing output.
|
|
46
|
-
|
|
47
|
-
### OFTR-004.3: Create Profile Command
|
|
48
|
-
|
|
49
|
-
1. Outfitter MUST provide a `profile create` command.
|
|
50
|
-
2. The `profile create` command MUST require a destination scope or destination path.
|
|
51
|
-
3. The `profile create` command MUST require a profile name.
|
|
52
|
-
4. The `profile create` command MUST create a placeholder profile folder with a valid `profile.yml` file.
|
|
53
|
-
5. The `profile create` command SHOULD create conventional subfolders for common profile resources.
|
|
54
|
-
|
|
55
|
-
### OFTR-004.4: Command Object Implementation
|
|
56
|
-
|
|
57
|
-
1. All CLI command entry points MUST execute command objects rather than duplicate implementation logic in parser callbacks.
|
|
58
|
-
2. Command objects MUST accept typed input objects rather than reading directly from `process.argv`.
|
|
59
|
-
3. Command objects SHOULD receive filesystem, settings, profile, and process dependencies through constructors or equivalent dependency injection.
|
|
60
|
-
4. The `profile create` parser entry point MUST execute the profile-creation command object.
|
|
61
|
-
|
|
62
|
-
### OFTR-004.5: List Profiles Command
|
|
63
|
-
|
|
64
|
-
1. Outfitter MUST provide a `profile list` command.
|
|
65
|
-
2. The `profile list` command MUST read and validate settings before listing profiles.
|
|
66
|
-
3. The `profile list` command MUST list unique profile IDs from configured local and cached remote profile sources.
|
|
67
|
-
4. When multiple configured sources define the same profile ID, the listed profile metadata MUST come from the highest-precedence loaded definition.
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# OFTR-005: Run Command and Composite profile Lifecycle
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
The `run` command assembles a temporary agent-specific configuration directory called a composite profile, launches the selected agent CLI, and keeps Outfitter alive to manage the composite profile while the child process runs.
|
|
6
|
-
|
|
7
|
-
## Requirements
|
|
8
|
-
|
|
9
|
-
### OFTR-005.1: Run Command Defaults
|
|
10
|
-
|
|
11
|
-
1. Outfitter MUST provide a `run` command.
|
|
12
|
-
2. `run` MUST be the default command when no command is specified.
|
|
13
|
-
3. The default command behavior MUST be implemented with Commander rather than a custom `process.argv` parser.
|
|
14
|
-
4. The `run` command MUST accept `-p` and `--profile` options for selecting the profile.
|
|
15
|
-
5. The `run` command MUST use the resolved default profile when no profile option is provided.
|
|
16
|
-
6. The `run` command MUST pass unrecognized arguments through to the selected agent CLI unaltered.
|
|
17
|
-
7. When invoked before user setup has created `~/.outfitter/settings.yml`, the default `run` command MUST print `` `outfitter setup` has not been run yet - running now `` and execute setup before resolving the profile.
|
|
18
|
-
|
|
19
|
-
### OFTR-005.2: Composite profile Definition
|
|
20
|
-
|
|
21
|
-
1. Outfitter MUST call the dynamically assembled runtime configuration directory a `composite profile`.
|
|
22
|
-
2. A composite profile MUST be scoped to a resolved profile and a selected agent CLI.
|
|
23
|
-
3. Outfitter MUST create composite profile directories under the system temporary directory.
|
|
24
|
-
4. Outfitter SHOULD use composite profile paths that include a run-specific identifier to avoid collisions between concurrent runs.
|
|
25
|
-
|
|
26
|
-
### OFTR-005.3: Composite profile Assembly
|
|
27
|
-
|
|
28
|
-
1. Outfitter MUST assemble the composite profile from resolved profile layers in precedence order.
|
|
29
|
-
2. Outfitter MUST combine generic profile controls with CLI-specific overrides.
|
|
30
|
-
3. Each logical generated file in the composite profile MUST have an object instance representing it.
|
|
31
|
-
4. Each composite profile file object MUST know its source inputs and generated output path.
|
|
32
|
-
5. Each composite profile file object SHOULD expose its merge or transform strategy.
|
|
33
|
-
|
|
34
|
-
### OFTR-005.4: Composite profile Watching
|
|
35
|
-
|
|
36
|
-
1. Outfitter MUST keep its process alive while the child agent CLI is running.
|
|
37
|
-
2. Outfitter MUST use `fs.watch` or an equivalent Node file watching mechanism on composite profile input files while the child process is running.
|
|
38
|
-
3. Outfitter MUST update generated composite profile files when watched inputs change and the generated output path remains inside the composite profile root.
|
|
39
|
-
4. Outfitter MUST warn when a live update cannot be applied because regeneration or composite profile-root path validation fails.
|
|
40
|
-
|
|
41
|
-
### OFTR-005.5: Unsupported Controls and Strict Mode
|
|
42
|
-
|
|
43
|
-
1. Outfitter MUST write a warning to stderr when a profile requests a control that the selected agent adapter cannot support.
|
|
44
|
-
2. The `run` command MUST accept a `--strict` option.
|
|
45
|
-
3. When `--strict` is enabled, unsupported controls MUST cause composite profile assembly to fail instead of only warning.
|
|
46
|
-
4. Strict failures MUST identify the unsupported control and selected agent CLI.
|
|
47
|
-
|
|
48
|
-
### OFTR-005.6: Composite profile State Persistence
|
|
49
|
-
|
|
50
|
-
1. Profiles MAY define `state_persistence` entries that map adapter-declared state paths to persistence strategies.
|
|
51
|
-
2. Outfitter MUST validate `state_persistence` values at profile read boundaries.
|
|
52
|
-
3. Before launch, Outfitter MUST resolve each adapter-declared state path to either a profile override strategy or the adapter default strategy.
|
|
53
|
-
4. Outfitter MUST reject profile `state_persistence` keys that are not declared by the selected adapter.
|
|
54
|
-
5. Outfitter MUST reject strategies that are not allowed for the adapter-declared state path.
|
|
55
|
-
6. For `symlink` strategy paths, Outfitter MUST materialize the composite profile path as a symlink to the resolved profile or native CLI source path.
|
|
56
|
-
7. For non-persistent strategies, Outfitter MUST materialize normal temporary composite profile paths and detect writes after the child agent exits.
|
|
57
|
-
8. Unknown writes MUST be governed by the adapter's `unknown` pseudo-path strategy and MUST NOT be persisted by symlink.
|
|
58
|
-
9. Outfitter MUST warn for `warn`, `prompt`, and symlink-replacement state write issues, fail for `error` state write issues, and ignore `discard` state writes.
|
|
59
|
-
10. State path materialization MUST reject paths that escape the composite profile root.
|
|
60
|
-
11. During live composite profile updates, Outfitter MUST update generated composite profile files without re-materializing declared state paths so post-launch write detection can still observe agent changes to those paths.
|