@ai-outfitter/outfitter 0.3.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 (156) hide show
  1. package/LICENSE.md +58 -0
  2. package/README.md +256 -0
  3. package/dist/agents/AdapterProfileControls.d.ts +20 -0
  4. package/dist/agents/AdapterProfileControls.js +63 -0
  5. package/dist/agents/AdapterProfileControls.js.map +1 -0
  6. package/dist/agents/AdapterStatePaths.d.ts +12 -0
  7. package/dist/agents/AdapterStatePaths.js +44 -0
  8. package/dist/agents/AdapterStatePaths.js.map +1 -0
  9. package/dist/agents/AgentAdapter.d.ts +32 -0
  10. package/dist/agents/AgentAdapter.js +2 -0
  11. package/dist/agents/AgentAdapter.js.map +1 -0
  12. package/dist/agents/AgentRegistry.d.ts +6 -0
  13. package/dist/agents/AgentRegistry.js +17 -0
  14. package/dist/agents/AgentRegistry.js.map +1 -0
  15. package/dist/agents/LaunchResources.d.ts +13 -0
  16. package/dist/agents/LaunchResources.js +35 -0
  17. package/dist/agents/LaunchResources.js.map +1 -0
  18. package/dist/agents/ResourceIdentity.d.ts +2 -0
  19. package/dist/agents/ResourceIdentity.js +51 -0
  20. package/dist/agents/ResourceIdentity.js.map +1 -0
  21. package/dist/agents/claude/ClaudeAdapter.d.ts +2 -0
  22. package/dist/agents/claude/ClaudeAdapter.js +117 -0
  23. package/dist/agents/claude/ClaudeAdapter.js.map +1 -0
  24. package/dist/agents/claude/ClaudeCompositeProfileWriter.d.ts +5 -0
  25. package/dist/agents/claude/ClaudeCompositeProfileWriter.js +7 -0
  26. package/dist/agents/claude/ClaudeCompositeProfileWriter.js.map +1 -0
  27. package/dist/agents/pi/PiAdapter.d.ts +2 -0
  28. package/dist/agents/pi/PiAdapter.js +229 -0
  29. package/dist/agents/pi/PiAdapter.js.map +1 -0
  30. package/dist/agents/pi/PiCompositeProfileWriter.d.ts +5 -0
  31. package/dist/agents/pi/PiCompositeProfileWriter.js +7 -0
  32. package/dist/agents/pi/PiCompositeProfileWriter.js.map +1 -0
  33. package/dist/agents/pi/PiMcpConfig.d.ts +2 -0
  34. package/dist/agents/pi/PiMcpConfig.js +114 -0
  35. package/dist/agents/pi/PiMcpConfig.js.map +1 -0
  36. package/dist/agents/pi/PiSettingsMergePolicy.d.ts +17 -0
  37. package/dist/agents/pi/PiSettingsMergePolicy.js +59 -0
  38. package/dist/agents/pi/PiSettingsMergePolicy.js.map +1 -0
  39. package/dist/cli/OutfitterCli.d.ts +4 -0
  40. package/dist/cli/OutfitterCli.js +32 -0
  41. package/dist/cli/OutfitterCli.js.map +1 -0
  42. package/dist/cli/commands/CommandObject.d.ts +11 -0
  43. package/dist/cli/commands/CommandObject.js +5 -0
  44. package/dist/cli/commands/CommandObject.js.map +1 -0
  45. package/dist/cli/commands/FirstRunWelcomeProfile.d.ts +11 -0
  46. package/dist/cli/commands/FirstRunWelcomeProfile.js +107 -0
  47. package/dist/cli/commands/FirstRunWelcomeProfile.js.map +1 -0
  48. package/dist/cli/commands/PiLoginLaunch.d.ts +10 -0
  49. package/dist/cli/commands/PiLoginLaunch.js +76 -0
  50. package/dist/cli/commands/PiLoginLaunch.js.map +1 -0
  51. package/dist/cli/commands/RunCommand.d.ts +30 -0
  52. package/dist/cli/commands/RunCommand.js +299 -0
  53. package/dist/cli/commands/RunCommand.js.map +1 -0
  54. package/dist/cli/commands/SetupCommand.d.ts +34 -0
  55. package/dist/cli/commands/SetupCommand.js +379 -0
  56. package/dist/cli/commands/SetupCommand.js.map +1 -0
  57. package/dist/cli/commands/SyncCommand.d.ts +28 -0
  58. package/dist/cli/commands/SyncCommand.js +178 -0
  59. package/dist/cli/commands/SyncCommand.js.map +1 -0
  60. package/dist/cli/commands/WelcomeCommand.d.ts +54 -0
  61. package/dist/cli/commands/WelcomeCommand.js +214 -0
  62. package/dist/cli/commands/WelcomeCommand.js.map +1 -0
  63. package/dist/cli/commands/profile/Command.d.ts +6 -0
  64. package/dist/cli/commands/profile/Command.js +21 -0
  65. package/dist/cli/commands/profile/Command.js.map +1 -0
  66. package/dist/cli/commands/profile/CreateCommand.d.ts +19 -0
  67. package/dist/cli/commands/profile/CreateCommand.js +115 -0
  68. package/dist/cli/commands/profile/CreateCommand.js.map +1 -0
  69. package/dist/cli/commands/profile/ListCommand.d.ts +17 -0
  70. package/dist/cli/commands/profile/ListCommand.js +85 -0
  71. package/dist/cli/commands/profile/ListCommand.js.map +1 -0
  72. package/dist/cli/commands/profile/Shared.d.ts +9 -0
  73. package/dist/cli/commands/profile/Shared.js +10 -0
  74. package/dist/cli/commands/profile/Shared.js.map +1 -0
  75. package/dist/cli.d.ts +3 -0
  76. package/dist/cli.js +22 -0
  77. package/dist/cli.js.map +1 -0
  78. package/dist/compositeProfile/CompositeProfile.d.ts +8 -0
  79. package/dist/compositeProfile/CompositeProfile.js +6 -0
  80. package/dist/compositeProfile/CompositeProfile.js.map +1 -0
  81. package/dist/compositeProfile/CompositeProfileAssembler.d.ts +12 -0
  82. package/dist/compositeProfile/CompositeProfileAssembler.js +32 -0
  83. package/dist/compositeProfile/CompositeProfileAssembler.js.map +1 -0
  84. package/dist/compositeProfile/CompositeProfileFile.d.ts +16 -0
  85. package/dist/compositeProfile/CompositeProfileFile.js +16 -0
  86. package/dist/compositeProfile/CompositeProfileFile.js.map +1 -0
  87. package/dist/compositeProfile/CompositeProfileTemplate.d.ts +15 -0
  88. package/dist/compositeProfile/CompositeProfileTemplate.js +65 -0
  89. package/dist/compositeProfile/CompositeProfileTemplate.js.map +1 -0
  90. package/dist/compositeProfile/CompositeProfileWatcher.d.ts +18 -0
  91. package/dist/compositeProfile/CompositeProfileWatcher.js +46 -0
  92. package/dist/compositeProfile/CompositeProfileWatcher.js.map +1 -0
  93. package/dist/compositeProfile/StatePersistence.d.ts +24 -0
  94. package/dist/compositeProfile/StatePersistence.js +224 -0
  95. package/dist/compositeProfile/StatePersistence.js.map +1 -0
  96. package/dist/merge/ArrayMergePolicy.d.ts +8 -0
  97. package/dist/merge/ArrayMergePolicy.js +45 -0
  98. package/dist/merge/ArrayMergePolicy.js.map +1 -0
  99. package/dist/merge/SettingsValueMerger.d.ts +11 -0
  100. package/dist/merge/SettingsValueMerger.js +34 -0
  101. package/dist/merge/SettingsValueMerger.js.map +1 -0
  102. package/dist/profiles/Profile.d.ts +32 -0
  103. package/dist/profiles/Profile.js +7 -0
  104. package/dist/profiles/Profile.js.map +1 -0
  105. package/dist/profiles/ProfileCache.d.ts +8 -0
  106. package/dist/profiles/ProfileCache.js +36 -0
  107. package/dist/profiles/ProfileCache.js.map +1 -0
  108. package/dist/profiles/ProfileLoader.d.ts +24 -0
  109. package/dist/profiles/ProfileLoader.js +169 -0
  110. package/dist/profiles/ProfileLoader.js.map +1 -0
  111. package/dist/profiles/ProfileMerger.d.ts +20 -0
  112. package/dist/profiles/ProfileMerger.js +97 -0
  113. package/dist/profiles/ProfileMerger.js.map +1 -0
  114. package/dist/profiles/ProfileSource.d.ts +35 -0
  115. package/dist/profiles/ProfileSource.js +13 -0
  116. package/dist/profiles/ProfileSource.js.map +1 -0
  117. package/dist/schemas/profile-source.schema.json +29 -0
  118. package/dist/schemas/profile.schema.json +115 -0
  119. package/dist/schemas/settings.schema.json +37 -0
  120. package/dist/settings/Settings.d.ts +17 -0
  121. package/dist/settings/Settings.js +5 -0
  122. package/dist/settings/Settings.js.map +1 -0
  123. package/dist/settings/SettingsLoader.d.ts +33 -0
  124. package/dist/settings/SettingsLoader.js +129 -0
  125. package/dist/settings/SettingsLoader.js.map +1 -0
  126. package/dist/settings/SettingsMerger.d.ts +2 -0
  127. package/dist/settings/SettingsMerger.js +31 -0
  128. package/dist/settings/SettingsMerger.js.map +1 -0
  129. package/dist/validation/SchemaValidator.d.ts +11 -0
  130. package/dist/validation/SchemaValidator.js +36 -0
  131. package/dist/validation/SchemaValidator.js.map +1 -0
  132. package/dist/validation/YamlDocument.d.ts +13 -0
  133. package/dist/validation/YamlDocument.js +11 -0
  134. package/dist/validation/YamlDocument.js.map +1 -0
  135. package/doc/.deepreview +30 -0
  136. package/doc/architecture.md +834 -0
  137. package/doc/controllable-elements.md +162 -0
  138. package/doc/file_structure.md +133 -0
  139. package/doc/integration_test_system.md +214 -0
  140. package/doc/specs/validating_requirements_with_rules.md +55 -0
  141. package/doc/state_writeback_strategy.md +334 -0
  142. package/package.json +73 -0
  143. package/requirements/OFTR-001-project-foundation.md +53 -0
  144. package/requirements/OFTR-002-settings.md +65 -0
  145. package/requirements/OFTR-003-profiles.md +51 -0
  146. package/requirements/OFTR-004-sync-and-setup.md +57 -0
  147. package/requirements/OFTR-005-run-and-composite-profile.md +60 -0
  148. package/requirements/OFTR-006-agent-adapters.md +64 -0
  149. package/requirements/OFTR-007-controllable-elements.md +32 -0
  150. package/requirements/OFTR-008-requirements-governance.md +42 -0
  151. package/requirements/OFTR-009-release-publishing.md +25 -0
  152. package/requirements/OFTR-010-onboarding-welcome.md +38 -0
  153. package/src/schemas/SchemaDocument.ts +20 -0
  154. package/src/schemas/profile-source.schema.json +29 -0
  155. package/src/schemas/profile.schema.json +115 -0
  156. package/src/schemas/settings.schema.json +37 -0
@@ -0,0 +1,60 @@
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.
@@ -0,0 +1,64 @@
1
+ # OFTR-006: Agent Adapters, Pi Support, and Claude Code Support
2
+
3
+ ## Overview
4
+
5
+ Agent adapters translate generic Outfitter profile controls into native configuration files, environment variables, and command-line arguments for specific agent CLIs.
6
+ Pi is the default and primary supported adapter; Claude Code is also supported through a dedicated adapter.
7
+
8
+ ## Requirements
9
+
10
+ ### OFTR-006.1: Adapter Boundary
11
+
12
+ 1. Outfitter MUST define an agent adapter abstraction for CLI-specific composite profile assembly and launch command generation.
13
+ 2. Each adapter MUST expose an identifier for the agent CLI it supports.
14
+ 3. Each adapter MUST report which controllable elements it supports.
15
+ 4. Each adapter MUST return warnings for profile controls it cannot translate.
16
+ 5. Outfitter SHOULD keep generic profile resolution independent from adapter-specific file generation.
17
+
18
+ ### OFTR-006.2: Supported Adapter Availability
19
+
20
+ 1. Outfitter MUST support the `pi` agent CLI on day one.
21
+ 2. Outfitter MAY document other agent CLIs as roadmap adapters before implementing them.
22
+ 3. Non-pi adapters MUST NOT be presented as supported until their adapter implementation and tests exist.
23
+ 4. When generic Outfitter terminology conflicts with pi terminology, the pi adapter SHOULD prefer pi naming for generated pi artifacts and user-facing pi diagnostics.
24
+ 5. Outfitter MUST keep `pi` as the default adapter when no adapter is selected explicitly or through settings.
25
+ 6. Outfitter MUST support Claude Code through a `claude` adapter once implementation and tests are present.
26
+
27
+ ### OFTR-006.3: Pi Launch Controls
28
+
29
+ 1. The pi adapter MUST use `PI_CODING_AGENT_DIR` as the primary profile-scoped pi configuration boundary.
30
+ 2. The pi adapter MUST support profile-controlled environment variables.
31
+ 3. The pi adapter MUST support profile-controlled pi CLI arguments.
32
+ 4. The pi adapter SHOULD support `PI_CODING_AGENT_SESSION_DIR` or `--session-dir` for session location control.
33
+ 5. The pi adapter SHOULD support `--extension` or `-e` for explicit extension injection.
34
+ 6. The pi adapter SHOULD support `--skill` for explicit skill injection.
35
+ 7. The pi adapter SHOULD support `--prompt-template` for prompt template injection.
36
+ 8. The pi adapter SHOULD support `--system-prompt` and `--append-system-prompt` for prompt control.
37
+ 9. The pi adapter SHOULD support pi model, provider, and thinking controls where native pi flags exist.
38
+ 10. The pi adapter MUST merge `.mcp.json` files from contributing `cli_specific/pi/` profile folders into the composite profile, adding unique array entries by identity while keeping the last entry for duplicate identities.
39
+ 11. The pi adapter MUST make native Pi `models.json` available inside the composite profile so custom providers and model definitions are visible before Pi resolves `--provider` and `--model` flags.
40
+
41
+ ### OFTR-006.4: Pi Startup Boundary
42
+
43
+ 1. Outfitter MUST NOT rely on pi extensions to choose the initial pi configuration directory.
44
+ 2. Outfitter MUST choose pi configuration paths before launching pi.
45
+ 3. Outfitter MAY use explicit bootstrap extensions for behavior that can run after pi has discovered its initial configuration directory.
46
+ 4. Outfitter MUST document warnings when a requested pi control cannot be applied because pi startup order makes it impossible.
47
+
48
+ ### OFTR-006.5: Claude Code Launch Controls
49
+
50
+ 1. The Claude Code adapter MUST use `CLAUDE_CONFIG_DIR` as the primary profile-scoped Claude Code configuration boundary.
51
+ 2. The Claude Code adapter MUST launch the native `claude` command.
52
+ 3. The Claude Code adapter MUST support profile-controlled environment variables.
53
+ 4. The Claude Code adapter MUST support profile-controlled pass-through Claude Code CLI arguments.
54
+ 5. The Claude Code adapter SHOULD support `--model`, `--effort`, `--system-prompt`, `--append-system-prompt`, and `--plugin-dir` where native Claude Code flags exist.
55
+ 6. The Claude Code adapter SHOULD support `controls.session_directory` and `controls.claude.session_directory` by routing Claude `projects/` session state through Outfitter state persistence.
56
+ 7. The Claude Code adapter MUST return unsupported-control warnings for requested generic or `controls.claude` controls that it cannot translate.
57
+
58
+ ### OFTR-006.6: Pi Settings Reconciliation
59
+
60
+ 1. When profile-controlled Pi extensions duplicate native Pi `settings.json` package entries, the pi adapter MUST avoid launching pi with both copies enabled.
61
+ 2. The pi adapter MUST compare duplicate Pi extension and package entries by normalized resource identity rather than raw source string.
62
+ 3. The pi adapter MUST preserve unrelated Pi settings and unrelated package entries when generating a reconciled runtime `settings.json`.
63
+ 4. The pi adapter MUST keep reconciled runtime `settings.json` writes non-durable and declared so they are discarded without being reported as unknown state.
64
+ 5. The pi adapter MUST fall back to native Pi `settings.json` state persistence when reconciliation is unnecessary or the settings file cannot be interpreted safely.
@@ -0,0 +1,32 @@
1
+ # OFTR-007: Controllable Elements Documentation
2
+
3
+ ## Overview
4
+
5
+ Outfitter maintains a generic cross-agent-CLI vocabulary for profile-controlled concepts.
6
+ This vocabulary is documented separately from implementation details so companies can reason about profiles across multiple agent CLIs.
7
+
8
+ ## Requirements
9
+
10
+ ### OFTR-007.1: Documentation File
11
+
12
+ 1. The project MUST include documentation with the header `Controllable Elements`.
13
+ 2. The controllable elements documentation MUST define each generic controllable aspect as a named term.
14
+ 3. Each defined term MUST describe the equivalent name or mechanism for pi.
15
+ 4. Each defined term SHOULD describe the equivalent name or mechanism for other major CLIs when those mappings are known.
16
+
17
+ ### OFTR-007.2: Support Matrix
18
+
19
+ 1. The controllable elements documentation MUST include a support matrix table.
20
+ 2. The support matrix MUST contain one row for each defined controllable aspect.
21
+ 3. The support matrix MUST contain one column for each documented agent CLI.
22
+ 4. Each support matrix cell MUST contain exactly one of `Unsupported`, `Supported`, or `Roadmap`.
23
+ 5. Pi MUST be the only CLI with `Supported` entries until another adapter is implemented and tested.
24
+
25
+ ### OFTR-007.3: Initial Controllable Aspects
26
+
27
+ 1. The documentation MUST include an Agent Config Directory controllable element.
28
+ 2. The documentation MUST include a Session Directory controllable element.
29
+ 3. The documentation MUST include Extensions, Skills, and Prompt Templates controllable elements.
30
+ 4. The documentation MUST include System Prompt and Appended System Prompt controllable elements.
31
+ 5. The documentation MUST include Model Selection and Credentials and Environment controllable elements.
32
+ 6. The documentation MUST include Tool Availability, Context Files, Theme or UI Presentation, Project Override Policy, Working Directory, Pass-through Arguments, and Bootstrap Hook controllable elements.
@@ -0,0 +1,42 @@
1
+ # OFTR-008: Requirements Governance
2
+
3
+ ## Overview
4
+
5
+ Outfitter requirements define reviewable project obligations.
6
+ Each requirement should be traceable to TypeScript implementation, tests, DeepSchemas, or DeepReview rules depending on the appropriate validation mechanism.
7
+
8
+ ## Requirements
9
+
10
+ ### OFTR-008.1: Requirement File Format
11
+
12
+ 1. Requirement files MUST live under `requirements/` and use filenames matching `OFTR-NNN-<topic>.md`.
13
+ 2. Requirement files MUST begin with a top-level heading matching `# OFTR-NNN: Title`.
14
+ 3. Requirement files MUST include an `## Overview` section before requirements.
15
+ 4. Requirement files MUST include an `## Requirements` section.
16
+ 5. Requirement section headings MUST use the format `### OFTR-NNN.M: Title`.
17
+ 6. Requirement statements MUST use RFC 2119 keywords such as MUST, MUST NOT, SHOULD, SHOULD NOT, MAY, REQUIRED, RECOMMENDED, or OPTIONAL.
18
+ 7. Requirement section ID numbering within each file MUST be sequential without gaps.
19
+ 8. Each requirement MUST be specific enough to verify by automated test, DeepSchema, DeepReview rule, or direct reviewer judgment.
20
+
21
+ ### OFTR-008.2: Validation Mechanism Selection
22
+
23
+ 1. Machine-verifiable requirements MUST be validated by automated TypeScript tests when the implementation exists.
24
+ 2. Single-file semantic requirements SHOULD be validated by anonymous DeepSchemas placed next to the governed file.
25
+ 3. Broad judgment-based requirements SHOULD be validated by `.deepreview` rules.
26
+ 4. Tests MUST NOT use fragile keyword checks to pretend to validate judgment-based requirements.
27
+ 5. Review rules SHOULD NOT ask reviewers to verify exact values, paths, or schema shapes that an automated test or JSON Schema can verify deterministically.
28
+
29
+ ### OFTR-008.3: Test Traceability Comments
30
+
31
+ 1. Tests that validate a formal requirement MUST include a traceability comment immediately before the test case or test block.
32
+ 2. Traceability comments MUST identify at least one requirement ID using the pattern `OFTR-NNN.M`.
33
+ 3. Traceability comments MUST state that the test validates a hard requirement and MUST NOT be modified unless the requirement changes.
34
+ 4. Test comments MUST describe durable behavior or policy intent rather than transient line numbers, pull request numbers, or current-diff context.
35
+ 5. Test comments MUST be updated or removed when the tested behavior changes.
36
+
37
+ ### OFTR-008.4: Traceability Reviews
38
+
39
+ 1. Changes to requirement files MUST trigger review of requirement formatting and traceability.
40
+ 2. Changes to TypeScript source or tests SHOULD trigger review for missing requirement coverage when they introduce or change product behavior.
41
+ 3. Changes to DeepSchemas or `.deepreview` policies MUST preserve references to the requirement IDs they enforce when applicable.
42
+ 4. The requirements DeepSchema MUST include a filename regex that matches the `OFTR-NNN-<topic>.md` naming style.
@@ -0,0 +1,25 @@
1
+ # OFTR-009: Release Publishing
2
+
3
+ ## Overview
4
+
5
+ Outfitter release publishing prepares package metadata from a GitHub release tag and publishes the `@ai-outfitter/outfitter` npm package through GitHub Actions.
6
+
7
+ ## Requirements
8
+
9
+ ### OFTR-009.1: Release Metadata Synchronization
10
+
11
+ 1. The release metadata synchronization script MUST accept a release version from an explicit argument, `OUTFITTER_RELEASE_VERSION`, or `GITHUB_REF_NAME`, in that precedence order.
12
+ 2. The release metadata synchronization script MUST normalize a leading `v` from release tags before writing package metadata.
13
+ 3. The release metadata synchronization script MUST reject invalid Semantic Versioning values before mutating package metadata.
14
+ 4. The release metadata synchronization script MUST update the root `package.json` version, root `package-lock.json` version, and `package-lock.json` root package entry version to the same normalized release version.
15
+ 5. The release metadata synchronization script MUST verify that the root package metadata it prepares belongs to the `@ai-outfitter/outfitter` npm package.
16
+ 6. The release metadata synchronization script MUST fail with an actionable error when required package-lock root package metadata is missing.
17
+
18
+ ### OFTR-009.2: Npm Release Workflow
19
+
20
+ 1. The npm release workflow MUST run when a GitHub release is published.
21
+ 2. The npm release workflow MUST install dependencies with `npm ci` before publishing.
22
+ 3. The npm release workflow MUST synchronize package metadata from the GitHub release tag before publishing.
23
+ 4. The npm release workflow MUST run CI checks before publishing.
24
+ 5. The npm release workflow MUST build the package before publishing.
25
+ 6. The npm release workflow MUST publish the public `@ai-outfitter/outfitter` package to the npm registry using an npm token secret.
@@ -0,0 +1,38 @@
1
+ # OFTR-010: Onboarding Welcome
2
+
3
+ ## Overview
4
+
5
+ Outfitter welcome onboarding guides a new user through the minimum choices needed to start productive Pi sessions, including an initial role and a recommended loadout of extensions and skills.
6
+
7
+ ## Requirements
8
+
9
+ ### OFTR-010.1: Welcome Text
10
+
11
+ 1. Welcome text MUST be shown to the user explaining what Outfitter and Pi are.
12
+
13
+ > Pi is a heavily customizable coding harness.
14
+ > The next few questions will configure Outfitter to best suit your workflow.
15
+
16
+ ### OFTR-010.2: Role Selection
17
+
18
+ 1. The welcome onboarding flow MUST ask the user to choose an initial role for the Outfitter-managed agent session.
19
+ 2. Role choices MUST align with Outfitter's built-in standard role catalog, not DeepWork review personas or a remote default profile source.
20
+ 3. The role selection prompt MUST include the currently available built-in standard profile roles, including `engineer` and `data_analyst` while those roles remain supported.
21
+ 4. The selected role MUST be captured as structured onboarding data so profile creation or profile selection can map it to the matching standard profile ID.
22
+ 5. If the selected role cannot be mapped to an available standard profile for the selected agent adapter, Outfitter MUST warn the user and choose a deterministic fallback role rather than silently ignoring the selection.
23
+
24
+ ### OFTR-010.3: Loadout Selection
25
+
26
+ 1. The welcome onboarding flow MUST recommend at least one default loadout for the selected role.
27
+ 2. A loadout MUST be represented as a named set of Pi extensions, skills, or package resources that Outfitter can translate into profile controls or profile-managed Pi configuration.
28
+ 3. The welcome onboarding flow MUST allow the user to accept the recommended loadout, select individual loadout items, or skip loadout installation.
29
+ 4. The default recommended loadout MUST include `git:github.com/ai-outfitter/ulta-tasklist`, `git:github.com/ai-outfitter/deepwork`, `npm:pi-subagents`, and `npm:pi-mcp-adapter` while those packages remain available.
30
+ 5. Loadout installation MUST be captured as structured onboarding data so future profile creation can install the selected extensions, skills, or package resources deterministically.
31
+ 6. If a loadout item is unavailable or unsupported by the selected agent adapter, Outfitter MUST warn the user and continue with the remaining selected loadout items unless strict onboarding validation is enabled.
32
+
33
+ ### OFTR-010.4: Pi Login Setup
34
+
35
+ 1. Before launching Pi after the welcome flow, Outfitter MUST detect whether native Pi appears to have no configured login state.
36
+ 2. If Pi is not logged in after the welcome flow, Outfitter MUST automatically invoke Pi's `/login` flow when Pi starts.
37
+ 3. When Outfitter launches Pi outside the welcome flow and Pi does not appear to be logged in, Outfitter MUST inform the user to run `/login` inside Pi.
38
+ 4. Pi login setup MUST NOT ask Outfitter to collect, echo, or persist provider API keys.
@@ -0,0 +1,20 @@
1
+ // Defines named JSON Schema document metadata for Outfitter persisted formats.
2
+ export interface SchemaDocument {
3
+ readonly id: string;
4
+ readonly path: string;
5
+ }
6
+
7
+ export const settingsSchemaDocument: SchemaDocument = {
8
+ id: 'settings',
9
+ path: 'src/schemas/settings.schema.json',
10
+ };
11
+
12
+ export const profileSchemaDocument: SchemaDocument = {
13
+ id: 'profile',
14
+ path: 'src/schemas/profile.schema.json',
15
+ };
16
+
17
+ export const profileSourceSchemaDocument: SchemaDocument = {
18
+ id: 'profile-source',
19
+ path: 'src/schemas/profile-source.schema.json',
20
+ };
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://outfitter.dev/schemas/profile-source.schema.json",
4
+ "title": "Outfitter profile source",
5
+ "type": "object",
6
+ "oneOf": [
7
+ {
8
+ "required": ["path"],
9
+ "not": { "anyOf": [{ "required": ["uri"] }, { "required": ["github"] }, { "required": ["ref"] }] }
10
+ },
11
+ { "required": ["uri"], "not": { "required": ["github"] } },
12
+ { "required": ["github"], "not": { "required": ["uri"] } }
13
+ ],
14
+ "properties": {
15
+ "path": { "type": "string", "minLength": 1 },
16
+ "uri": { "type": "string", "minLength": 1 },
17
+ "github": { "type": "string", "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$" },
18
+ "ref": { "type": "string", "minLength": 1 },
19
+ "only": {
20
+ "type": "array",
21
+ "items": { "type": "string", "minLength": 1 }
22
+ },
23
+ "except": {
24
+ "type": "array",
25
+ "items": { "type": "string", "minLength": 1 }
26
+ }
27
+ },
28
+ "additionalProperties": false
29
+ }
@@ -0,0 +1,115 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://outfitter.dev/schemas/profile.schema.json",
4
+ "title": "Outfitter profile",
5
+ "type": "object",
6
+ "properties": {
7
+ "id": {
8
+ "type": "string",
9
+ "pattern": "^[a-z0-9][a-z0-9._-]*[a-z0-9]$|^[a-z0-9]$"
10
+ },
11
+ "label": { "type": "string" },
12
+ "inherits": {
13
+ "type": "array",
14
+ "items": {
15
+ "type": "string",
16
+ "pattern": "^[a-z0-9][a-z0-9._-]*[a-z0-9]$|^[a-z0-9]$"
17
+ }
18
+ },
19
+ "state_persistence": {
20
+ "type": "object",
21
+ "additionalProperties": {
22
+ "enum": ["symlink", "discard", "warn", "error", "prompt"]
23
+ }
24
+ },
25
+ "controls": {
26
+ "type": "object",
27
+ "properties": {
28
+ "model": { "type": "string" },
29
+ "provider": { "type": "string" },
30
+ "thinking": { "type": "string" },
31
+ "args": {
32
+ "type": "array",
33
+ "items": { "type": "string" }
34
+ },
35
+ "session_directory": { "type": "string" },
36
+ "extensions": {
37
+ "type": "array",
38
+ "items": { "type": "string" }
39
+ },
40
+ "skills": {
41
+ "type": "array",
42
+ "items": { "type": "string" }
43
+ },
44
+ "prompt_template": { "type": "string" },
45
+ "system_prompt": { "type": "string" },
46
+ "append_system_prompt": { "type": "string" },
47
+ "environment": {
48
+ "type": "object",
49
+ "additionalProperties": { "type": "string" }
50
+ },
51
+ "pi": {
52
+ "type": "object",
53
+ "properties": {
54
+ "model": { "type": "string" },
55
+ "provider": { "type": "string" },
56
+ "thinking": { "type": "string" },
57
+ "args": {
58
+ "type": "array",
59
+ "items": { "type": "string" }
60
+ },
61
+ "session_directory": { "type": "string" },
62
+ "extensions": {
63
+ "type": "array",
64
+ "items": { "type": "string" }
65
+ },
66
+ "skills": {
67
+ "type": "array",
68
+ "items": { "type": "string" }
69
+ },
70
+ "prompt_template": { "type": "string" },
71
+ "system_prompt": { "type": "string" },
72
+ "append_system_prompt": { "type": "string" },
73
+ "allow_external_deepwork_jobs": { "type": "boolean" },
74
+ "environment": {
75
+ "type": "object",
76
+ "additionalProperties": { "type": "string" }
77
+ }
78
+ },
79
+ "additionalProperties": true
80
+ },
81
+ "claude": {
82
+ "type": "object",
83
+ "properties": {
84
+ "model": { "type": "string" },
85
+ "provider": { "type": "string" },
86
+ "thinking": { "type": "string" },
87
+ "args": {
88
+ "type": "array",
89
+ "items": { "type": "string" }
90
+ },
91
+ "session_directory": { "type": "string" },
92
+ "extensions": {
93
+ "type": "array",
94
+ "items": { "type": "string" }
95
+ },
96
+ "skills": {
97
+ "type": "array",
98
+ "items": { "type": "string" }
99
+ },
100
+ "prompt_template": { "type": "string" },
101
+ "system_prompt": { "type": "string" },
102
+ "append_system_prompt": { "type": "string" },
103
+ "environment": {
104
+ "type": "object",
105
+ "additionalProperties": { "type": "string" }
106
+ }
107
+ },
108
+ "additionalProperties": true
109
+ }
110
+ },
111
+ "additionalProperties": true
112
+ }
113
+ },
114
+ "additionalProperties": true
115
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://outfitter.dev/schemas/settings.schema.json",
4
+ "title": "Outfitter settings",
5
+ "type": "object",
6
+ "properties": {
7
+ "default_profile": { "type": "string", "minLength": 1 },
8
+ "default_agent": { "enum": ["pi", "claude"] },
9
+ "cache_directory": { "type": "string", "minLength": 1 },
10
+ "profile_sources": {
11
+ "type": "array",
12
+ "items": { "$ref": "profile-source.schema.json" }
13
+ },
14
+ "remote_settings": {
15
+ "type": "array",
16
+ "items": {
17
+ "type": "object",
18
+ "oneOf": [
19
+ { "required": ["uri", "path"], "not": { "required": ["github"] } },
20
+ { "required": ["github", "path"], "not": { "required": ["uri"] } }
21
+ ],
22
+ "properties": {
23
+ "path": { "type": "string", "minLength": 1 },
24
+ "uri": { "type": "string", "minLength": 1 },
25
+ "github": { "type": "string", "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$" },
26
+ "ref": { "type": "string", "minLength": 1 }
27
+ },
28
+ "additionalProperties": false
29
+ }
30
+ },
31
+ "custom_settings": {
32
+ "type": "object",
33
+ "description": "Arbitrary YAML-compatible values exposed to Outfitter compositeProfile templates as outfitter.custom_settings."
34
+ }
35
+ },
36
+ "additionalProperties": true
37
+ }