loadout-ai 0.1.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 (125) hide show
  1. package/LICENSE +21 -0
  2. package/MASTER_PLAN.md +1711 -0
  3. package/README.md +453 -0
  4. package/SECURITY.md +18 -0
  5. package/SIMPLE_PLAN.md +44 -0
  6. package/catalog/discovered.json +10469 -0
  7. package/catalog/packages.json +1150 -0
  8. package/dashboard/app.js +607 -0
  9. package/dashboard/index.html +249 -0
  10. package/dashboard/styles.css +384 -0
  11. package/dist/src/cli.js +2735 -0
  12. package/dist/src/core/active-policy.js +233 -0
  13. package/dist/src/core/active-set.js +382 -0
  14. package/dist/src/core/adapters.js +254 -0
  15. package/dist/src/core/adopt.js +92 -0
  16. package/dist/src/core/agent-health-score.js +475 -0
  17. package/dist/src/core/agent-inspection.js +152 -0
  18. package/dist/src/core/agent-versions.js +131 -0
  19. package/dist/src/core/api.js +90 -0
  20. package/dist/src/core/atomic-file.js +22 -0
  21. package/dist/src/core/audit.js +174 -0
  22. package/dist/src/core/benchmark-campaign.js +496 -0
  23. package/dist/src/core/benchmark-evidence.js +458 -0
  24. package/dist/src/core/benchmark-fixtures.js +1157 -0
  25. package/dist/src/core/benchmark-runner.js +301 -0
  26. package/dist/src/core/benchmark-trust.js +795 -0
  27. package/dist/src/core/canary.js +77 -0
  28. package/dist/src/core/candidate-intelligence.js +661 -0
  29. package/dist/src/core/catalog-coverage.js +85 -0
  30. package/dist/src/core/catalog-install.js +186 -0
  31. package/dist/src/core/catalog-release.js +286 -0
  32. package/dist/src/core/catalog.js +327 -0
  33. package/dist/src/core/codex-mcp.js +122 -0
  34. package/dist/src/core/community.js +86 -0
  35. package/dist/src/core/compatibility-intelligence.js +465 -0
  36. package/dist/src/core/completion.js +160 -0
  37. package/dist/src/core/components.js +138 -0
  38. package/dist/src/core/conversion.js +56 -0
  39. package/dist/src/core/credentials.js +377 -0
  40. package/dist/src/core/demo.js +136 -0
  41. package/dist/src/core/diff.js +83 -0
  42. package/dist/src/core/discovery-connector.js +165 -0
  43. package/dist/src/core/doctor.js +95 -0
  44. package/dist/src/core/ecosystem-import.js +1072 -0
  45. package/dist/src/core/evaluate.js +72 -0
  46. package/dist/src/core/file-lock.js +140 -0
  47. package/dist/src/core/freshness-alerts.js +230 -0
  48. package/dist/src/core/github-discovery.js +97 -0
  49. package/dist/src/core/github.js +148 -0
  50. package/dist/src/core/head-to-head.js +437 -0
  51. package/dist/src/core/health-score-evidence.js +169 -0
  52. package/dist/src/core/health.js +129 -0
  53. package/dist/src/core/improve.js +223 -0
  54. package/dist/src/core/install.js +233 -0
  55. package/dist/src/core/intelligence-feed-build.js +59 -0
  56. package/dist/src/core/intelligence-feed.js +353 -0
  57. package/dist/src/core/loadout-badge.js +55 -0
  58. package/dist/src/core/loadout-card.js +87 -0
  59. package/dist/src/core/manifest.js +307 -0
  60. package/dist/src/core/mcp-recipes.js +419 -0
  61. package/dist/src/core/mcp-registry-discovery.js +455 -0
  62. package/dist/src/core/mcp.js +287 -0
  63. package/dist/src/core/model-config.js +102 -0
  64. package/dist/src/core/observations.js +87 -0
  65. package/dist/src/core/outcomes.js +164 -0
  66. package/dist/src/core/package.js +225 -0
  67. package/dist/src/core/paths.js +214 -0
  68. package/dist/src/core/portable.js +130 -0
  69. package/dist/src/core/private-discovery.js +45 -0
  70. package/dist/src/core/profiles.js +255 -0
  71. package/dist/src/core/provenance.js +278 -0
  72. package/dist/src/core/ranking.js +104 -0
  73. package/dist/src/core/recommend.js +181 -0
  74. package/dist/src/core/registry-api.js +97 -0
  75. package/dist/src/core/registry.js +316 -0
  76. package/dist/src/core/release-claims.js +175 -0
  77. package/dist/src/core/remove.js +122 -0
  78. package/dist/src/core/review-queue.js +200 -0
  79. package/dist/src/core/runtime-tool-recipe.js +315 -0
  80. package/dist/src/core/runtime-tools.js +453 -0
  81. package/dist/src/core/safety.js +234 -0
  82. package/dist/src/core/sandbox.js +78 -0
  83. package/dist/src/core/scheduler.js +264 -0
  84. package/dist/src/core/share-report.js +85 -0
  85. package/dist/src/core/signing.js +115 -0
  86. package/dist/src/core/skill-compare.js +239 -0
  87. package/dist/src/core/skill-inventory.js +193 -0
  88. package/dist/src/core/skill-security.js +340 -0
  89. package/dist/src/core/skills-sh-discovery.js +336 -0
  90. package/dist/src/core/skills.js +208 -0
  91. package/dist/src/core/snapshot.js +210 -0
  92. package/dist/src/core/source.js +305 -0
  93. package/dist/src/core/state.js +300 -0
  94. package/dist/src/core/sync.js +348 -0
  95. package/dist/src/core/terminal.js +53 -0
  96. package/dist/src/core/transaction.js +211 -0
  97. package/dist/src/core/update-watch.js +39 -0
  98. package/dist/src/core/update.js +216 -0
  99. package/dist/src/core/upgrade.js +207 -0
  100. package/dist/src/dashboard.js +418 -0
  101. package/dist/src/shared/schemas.js +336 -0
  102. package/dist/src/shared/types.js +1 -0
  103. package/docs/ACTIVE_SET.md +53 -0
  104. package/docs/ACTIVE_SET_POLICY.md +45 -0
  105. package/docs/CANDIDATE_INTELLIGENCE.md +139 -0
  106. package/docs/CATALOG.md +78 -0
  107. package/docs/CATALOG_POLICY.md +41 -0
  108. package/docs/COMMUNITY_DISCOVERY.md +14 -0
  109. package/docs/COMPATIBILITY_POLICY.md +22 -0
  110. package/docs/CONVERSION_AND_SANDBOX.md +27 -0
  111. package/docs/CREDENTIAL_AND_UPDATE_POLICY.md +31 -0
  112. package/docs/DISCOVERED.md +280 -0
  113. package/docs/EVALUATION_PROTOCOL.md +40 -0
  114. package/docs/EVALUATION_PROTOCOL_V1.md +300 -0
  115. package/docs/FEATURE_TEST_MATRIX.md +802 -0
  116. package/docs/GITHUB_AUTHORIZATION.md +38 -0
  117. package/docs/HEAD_TO_HEAD_EVALUATION.md +79 -0
  118. package/docs/PROVENANCE_AND_COMPARISON.md +72 -0
  119. package/docs/PROVIDER_CONFIGURATION.md +45 -0
  120. package/docs/RELEASE_REVIEW.md +117 -0
  121. package/docs/SAFE_UPDATE_DEMO.md +25 -0
  122. package/docs/SCHEMA_DECISIONS.md +25 -0
  123. package/docs/TEAM_POLICY.md +18 -0
  124. package/docs/TESTING.md +190 -0
  125. package/package.json +82 -0
@@ -0,0 +1,802 @@
1
+ # Complete CLI feature test matrix
2
+
3
+ This matrix is the pre-release, founder-facing procedure for exercising Loadout's
4
+ public CLI without guessing which commands write files, use the network, start a
5
+ process, consume provider credit, or modify the host. It is generated from the
6
+ current `loadout --help` and command-specific help, not from a future product plan.
7
+
8
+ Run the automated gate first. Then use the disposable profile for every ordinary
9
+ feature. Only the final, explicitly labelled host-integration track should touch a
10
+ real credential store, scheduler, Docker daemon, or agent profile.
11
+
12
+ ## Safety legend
13
+
14
+ | Mark | Meaning |
15
+ | ---- | ------------------------------------------------------------------------------- |
16
+ | R | Read-only with respect to agent profiles. It may still read local files. |
17
+ | S | Writes only to `LOADOUT_HOME` or an explicitly supplied disposable path. |
18
+ | A | Writes to a disposable agent profile after `--yes`. A snapshot must be printed. |
19
+ | N | Uses the public network. GitHub rate limits may apply. |
20
+ | X | Starts an external process or server. |
21
+ | H | Mutates a host integration and is not isolated by `LOADOUT_HOME`. |
22
+ | $ | Makes an authenticated provider request that may consume API credit. |
23
+
24
+ `--yes`, `--apply`, `--approve-risk`, `--connect`, `--private`, `--write`, and
25
+ `--approve` are mutation or authority boundaries. Never add one merely to make a
26
+ preview “work.” Read its plan first.
27
+
28
+ ## 0. Prerequisites and disposable environment
29
+
30
+ Required everywhere:
31
+
32
+ - Node.js 20 or 22 and npm;
33
+ - Git for GitHub-backed package tests;
34
+ - a checkout of this repository with dependencies installed and `npm run build`
35
+ completed;
36
+ - internet access only for tests marked N.
37
+
38
+ Optional integrations:
39
+
40
+ - Docker for `sandbox-run`;
41
+ - macOS Keychain, Windows Credential Manager, or Linux Secret Service plus
42
+ `secret-tool` for credential tests;
43
+ - an OpenRouter key only for the optional paid model verification;
44
+ - `curl` for manually probing loopback HTTP services.
45
+
46
+ From the repository root, create a shell function that always invokes the built npm
47
+ entry point, even after commands change directories.
48
+
49
+ macOS or Linux:
50
+
51
+ ```bash
52
+ export LOADOUT_ROOT="$PWD"
53
+ npm ci
54
+ npm run build
55
+ loadout() { node "$LOADOUT_ROOT/dist/src/cli.js" "$@"; }
56
+
57
+ export TEST_ROOT="$(mktemp -d)"
58
+ export LOADOUT_USER_HOME="$TEST_ROOT/user"
59
+ export LOADOUT_HOME="$TEST_ROOT/state"
60
+ export TEST_PROJECT="$TEST_ROOT/project"
61
+ mkdir -p "$LOADOUT_USER_HOME/.codex" "$LOADOUT_USER_HOME/.claude" "$TEST_PROJECT"
62
+ printf '{"scripts":{"test":"vitest run"},"dependencies":{"zod":"latest"}}\n' \
63
+ > "$TEST_PROJECT/package.json"
64
+ ```
65
+
66
+ PowerShell:
67
+
68
+ ```powershell
69
+ $env:LOADOUT_ROOT = (Get-Location).Path
70
+ npm ci
71
+ npm run build
72
+ function loadout { node "$env:LOADOUT_ROOT/dist/src/cli.js" @args }
73
+
74
+ $env:TEST_ROOT = Join-Path $env:TEMP ("loadout-test-" + [guid]::NewGuid())
75
+ $env:LOADOUT_USER_HOME = Join-Path $env:TEST_ROOT "user"
76
+ $env:LOADOUT_HOME = Join-Path $env:TEST_ROOT "state"
77
+ $env:TEST_PROJECT = Join-Path $env:TEST_ROOT "project"
78
+ New-Item -ItemType Directory -Force `
79
+ (Join-Path $env:LOADOUT_USER_HOME ".codex"), `
80
+ (Join-Path $env:LOADOUT_USER_HOME ".claude"), `
81
+ $env:TEST_PROJECT | Out-Null
82
+ '{"scripts":{"test":"vitest run"},"dependencies":{"zod":"latest"}}' |
83
+ Set-Content (Join-Path $env:TEST_PROJECT "package.json")
84
+ ```
85
+
86
+ The empty `.codex` and `.claude` directories make those two virtual agents
87
+ detectable. They do not read or write the real profile.
88
+
89
+ The remaining transcripts use POSIX shell line continuations. The CLI names, options,
90
+ and expected results are identical on Windows. In PowerShell, omit `\`, use backtick
91
+ for a continued command, replace `mkdir -p <path>` with
92
+ `New-Item -ItemType Directory -Force <path>`, `cp` with `Copy-Item`, and a `(cd ...;
93
+ commands)` subshell with `Push-Location ...; try { commands } finally { Pop-Location
94
+ }`. Native credential and scheduling behavior remains platform-specific as described
95
+ in tracks 9 and 10.
96
+
97
+ Confirm isolation before any applied command:
98
+
99
+ ```bash
100
+ loadout status --json
101
+ loadout capabilities
102
+ ```
103
+
104
+ Expected: paths, if shown, are below `TEST_ROOT`; Codex and Claude Code are detected;
105
+ the capability table names native, adapted, and unsupported surfaces honestly.
106
+
107
+ ## 1. Automated release gate
108
+
109
+ Run the entire required gate with one command:
110
+
111
+ ```bash
112
+ npm run verify
113
+ ```
114
+
115
+ Use `npm run verify:full` when Playwright Chromium is installed and you also want the
116
+ optional dashboard browser check. The individual stages are listed below for focused
117
+ reruns and diagnosis.
118
+
119
+ | Command | Coverage | Expected result |
120
+ | ---------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------- |
121
+ | `npm run format:check` | Repository formatting | Exit 0; no files changed. |
122
+ | `npm run lint` | TypeScript lint rules | Exit 0. |
123
+ | `npm run typecheck` | TypeScript contract | Exit 0. |
124
+ | `npm test` | Unit, integration, native filesystem, safety, and regression suites | All tests pass. |
125
+ | `npm run test:e2e:cli` | Disposable scan → compare → optimize → apply → rollback journey | Prints a successful CLI product flow. |
126
+ | `npm run test:package` | `npm pack`, install outside the checkout, packaged CLI install/rollback | Prints package smoke success. |
127
+ | `npm run test:performance` | Seven scans of 1,000 real on-disk skill directories | p95 remains below the enforced five-second budget. |
128
+ | `npm run test:e2e:dashboard` | Loopback dashboard first-run browser test | Playwright passes; no real profile is used. |
129
+
130
+ The dashboard test needs a Playwright browser. If the browser executable is absent,
131
+ run `npx playwright install chromium` once; that download is not a Loadout product
132
+ side effect.
133
+
134
+ ## 2. Read-only inventory, ranking, and recommendation track (R; some N)
135
+
136
+ ```bash
137
+ loadout --help
138
+ loadout catalog --coverage --json
139
+ loadout catalog --explain superpowers
140
+ loadout search frontend --json
141
+ loadout profiles --json
142
+ loadout recommend --project "$TEST_PROJECT" --json
143
+ loadout doctor --json
144
+ loadout status --json
145
+ loadout versions --json
146
+ loadout list --json
147
+ loadout library --json
148
+ loadout health --explain --json
149
+ loadout report --json
150
+ loadout card --json
151
+ loadout outcomes --json
152
+ loadout capabilities --inspect --json
153
+ ```
154
+
155
+ Expected:
156
+
157
+ - catalog coverage reports technically screened and recommended counts separately,
158
+ all trust stages, component/install shapes, licenses, evidence, categories, and
159
+ overlap statistics;
160
+ - ranking explanation cites stored evidence and guardrails rather than claiming that
161
+ stars alone prove quality;
162
+ - recommendation reflects the disposable project's JavaScript/testing signals;
163
+ - empty-state commands return a valid report instead of inventing installations;
164
+ - privacy-safe reports contain no project paths, prompts, source code, or secrets.
165
+ - version evidence comes only from bounded sanitized read-only probes; explained
166
+ health lists contribution, cap, evidence, uncertainty, and remediation for every
167
+ dimension and gives missing evidence no credit;
168
+ - the card contains aggregate inventory and evidence coverage only, with an explicit
169
+ boundary against universal-quality or task-improvement claims.
170
+
171
+ Network variants must be run deliberately:
172
+
173
+ ```bash
174
+ loadout catalog --refresh --json
175
+ loadout health --updates --json
176
+ loadout scan --agents codex,claude-code --refresh-provenance --json
177
+ loadout compare brainstorming --offline --json
178
+ loadout discover --source mcp-registry --limit 10 --json
179
+ loadout discover --source skills-sh --limit 10 --json
180
+ ```
181
+
182
+ The first three use network access and may update history/provenance below
183
+ `LOADOUT_HOME`; after a **successful** complete provenance refresh, the reviewed
184
+ Superpowers `brainstorming` skill can be compared with `--offline` and no fetch. If a
185
+ rate limit interrupts the refresh, retry later rather than treating a partial index as
186
+ complete. A same-name match is evidence for comparison, not proof that a package is
187
+ universally better.
188
+
189
+ The official MCP Registry path is public identity/distribution discovery. The
190
+ skills.sh path needs its request-scoped `VERCEL_OIDC_TOKEN`; without one it must use a
191
+ previous complete cache or return an attributed `unavailable` result without making
192
+ an unauthenticated request. Neither source installs or promotes a lead.
193
+
194
+ ## 3. Package, manifest, lock, portability, and registry track (S/A)
195
+
196
+ Create a package _inside_ the test project so its manifest can be exported portably:
197
+
198
+ ```bash
199
+ mkdir -p "$TEST_PROJECT/packages"
200
+ loadout create "$TEST_PROJECT/packages/matrix-demo" \
201
+ --name matrix-demo --description "Disposable matrix package"
202
+ loadout pack "$TEST_PROJECT/packages/matrix-demo" --json
203
+ loadout publish "$TEST_PROJECT/packages/matrix-demo" --local
204
+ loadout search matrix-demo --json
205
+
206
+ loadout init --path "$TEST_PROJECT/loadout.json" --name matrix \
207
+ --agents codex,claude-code --scope project
208
+ (
209
+ cd "$TEST_PROJECT"
210
+ loadout add local-demo --manifest loadout.json --local \
211
+ --path packages/matrix-demo --agents codex,claude-code
212
+ loadout sync --manifest loadout.json --lock loadout.lock
213
+ loadout sync --manifest loadout.json --lock loadout.lock --yes
214
+ loadout audit --manifest loadout.json --lock loadout.lock --json
215
+ )
216
+ ```
217
+
218
+ Expected: `pack` returns a deterministic digest; local publication is immutable;
219
+ the first `sync` is a dry run; applied sync prints one snapshot; `audit` returns
220
+ `"valid": true`; skills appear only below the disposable profile.
221
+
222
+ Exercise desired-state editing and portability:
223
+
224
+ ```bash
225
+ (
226
+ cd "$TEST_PROJECT"
227
+ loadout lock --manifest loadout.json --output loadout.lock
228
+ loadout export portable.json --manifest loadout.json --lock loadout.lock
229
+ loadout import portable.json --manifest imported.json --lock imported.lock
230
+ loadout import portable.json --manifest imported.json --lock imported.lock --yes
231
+ loadout unadd local-demo --manifest imported.json
232
+ )
233
+ ```
234
+
235
+ Expected: import previews before writing; applied import snapshots destinations;
236
+ `unadd` changes desired state only and does not delete installed files.
237
+
238
+ The full authenticated remote-registry protocol, including wrong-token rejection,
239
+ immutable-version conflict rejection, exact digest download, risk approval, and the
240
+ HTTPS/non-loopback boundary, is reproducibly covered by:
241
+
242
+ ```bash
243
+ npx vitest run tests/registry-api.test.ts tests/package.test.ts
244
+ ```
245
+
246
+ Manual `registry-serve`/remote `publish` is an X test. After completing the throwaway
247
+ credential setup in track 9, start this in one terminal:
248
+
249
+ ```bash
250
+ loadout registry-serve --port 7331 \
251
+ --credential-keychain loadout-registry-test --credential-account tester
252
+ ```
253
+
254
+ Then publish from another terminal:
255
+
256
+ ```bash
257
+ loadout publish "$TEST_PROJECT/packages/matrix-demo" \
258
+ --registry-url http://127.0.0.1:7331 \
259
+ --credential-keychain loadout-registry-test --credential-account tester
260
+ ```
261
+
262
+ Never place the token on the command line. An identical version/content publish may
263
+ be accepted idempotently; changed content at the same version must be rejected. Stop
264
+ the server with Ctrl-C.
265
+
266
+ ## 4. Install, active-set, outcome, and rollback track (A; Maximum is N)
267
+
268
+ Exercise the new-user golden path before its constituent commands:
269
+
270
+ ```bash
271
+ loadout upgrade --mode stable --project "$TEST_PROJECT" --agents codex
272
+ loadout upgrade --mode stable --project "$TEST_PROJECT" --agents codex \
273
+ --yes
274
+ loadout health --explain --agents codex
275
+ loadout rollback
276
+ ```
277
+
278
+ Expected: the first command combines project signals, existing health, Agent Health
279
+ Score evidence, recommendations, exact immutable sources, target directories, safety
280
+ findings, and transaction guarantees without changing the profile. Apply prints one
281
+ snapshot, and rollback removes the managed bytes while preserving the virtual Codex
282
+ profile. If the preview requires risk approval, review the findings and repeat with
283
+ `--approve-risk`; never add it pre-emptively.
284
+
285
+ Create a second local package to give direct `plan`/`install` an unoccupied target;
286
+ the manifest-synced `local-demo` remains available for comparison:
287
+
288
+ ```bash
289
+ loadout create "$TEST_PROJECT/packages/direct-demo" \
290
+ --name direct-demo --description "Disposable direct-install package"
291
+ loadout plan --source "$TEST_PROJECT/packages/direct-demo" \
292
+ --package direct-demo --agents codex
293
+ loadout install --source "$TEST_PROJECT/packages/direct-demo" \
294
+ --package direct-demo --agents codex --yes
295
+ loadout list --json
296
+ loadout library --json
297
+ loadout scan --agents codex --json
298
+ loadout optimize --project "$TEST_PROJECT" --agents codex --limit 10 --json
299
+ loadout optimize --project "$TEST_PROJECT" --agents codex --limit 10 --yes
300
+ loadout activate --project "$TEST_PROJECT" --agents codex --limit 10 --json
301
+ ```
302
+
303
+ Expected: `plan` is read-only; install and applied optimize print snapshots; installed
304
+ bytes hash correctly; activate/optimize never activate an unreviewed or missing
305
+ library entry.
306
+
307
+ Use exact selectors printed by `library` for lifecycle and outcome commands:
308
+
309
+ ```bash
310
+ loadout disable direct-demo --agents codex
311
+ loadout disable direct-demo --agents codex --yes --json
312
+ loadout enable direct-demo --agents codex
313
+ loadout enable direct-demo --agents codex --yes --json
314
+ loadout outcome direct-demo/direct-demo --agent codex --task testing \
315
+ --result success
316
+ loadout outcomes --json
317
+ loadout share "$TEST_PROJECT/share.json"
318
+ loadout remove direct-demo
319
+ loadout remove direct-demo --yes
320
+ loadout remove local-demo --yes
321
+ loadout rollback --list
322
+ loadout rollback
323
+ ```
324
+
325
+ Every mutating lifecycle command previews first. `share.json` must be privacy-safe.
326
+ `remove` touches only Loadout-managed files. Rollback restores the most recent
327
+ snapshot, not arbitrary unmanaged content. Use `--force` only in a separate deliberate
328
+ drift test after manually changing a managed file.
329
+
330
+ Run the real reviewed catalog journey only after the local track passes:
331
+
332
+ ```bash
333
+ loadout setup --mode stable --agents codex
334
+ loadout setup --mode power --agents codex
335
+ loadout setup --mode maximum --agents codex
336
+ loadout setup --mode maximum --agents codex --yes --approve-risk
337
+ loadout library
338
+ loadout optimize --project "$TEST_PROJECT" --agents codex --limit 30
339
+ loadout optimize --project "$TEST_PROJECT" --agents codex --limit 30 --yes
340
+ ```
341
+
342
+ The previews fetch pinned public repositories but do not write agent skill targets.
343
+ Maximum downloads the full reviewed library; MCP-only packages remain explicit setup
344
+ items. `--approve-risk` acknowledges displayed static findings but does not execute
345
+ third-party repository scripts.
346
+
347
+ `loadout demo --json` is a shorter N smoke test. It creates its own isolated profile,
348
+ performs a real public-repository install and rollback, and must report that local
349
+ agent configuration was untouched. Add `--keep` only when you intend to inspect and
350
+ manually remove the printed demo directory.
351
+
352
+ ## 5. Existing-skill provenance, adoption, comparison, and freshness (R/S/A)
353
+
354
+ Copy one harmless skill into the disposable unmanaged profile, then inspect it:
355
+
356
+ ```bash
357
+ mkdir -p "$LOADOUT_USER_HOME/.agents/skills/unmanaged-demo"
358
+ cp "$TEST_PROJECT/packages/matrix-demo/skills/matrix-demo/SKILL.md" \
359
+ "$LOADOUT_USER_HOME/.agents/skills/unmanaged-demo/SKILL.md"
360
+ loadout scan --agents codex --json
361
+ loadout adopt unmanaged-demo --agent codex --json
362
+ loadout adopt unmanaged-demo --agent codex --yes --json
363
+ loadout compare unmanaged-demo --agent codex --offline --json
364
+ ```
365
+
366
+ Expected: scan labels the copy unmanaged; adoption preview does not change its bytes;
367
+ applied adoption records ownership and leaves its hash unchanged; comparison states
368
+ when evidence is insufficient rather than fabricating a winner.
369
+
370
+ The offline comparison requires the complete provenance index from track 2. If that
371
+ refresh was rate-limited, use `--refresh` later instead of expecting partial cache
372
+ state to pass as complete.
373
+
374
+ Freshness and replacement preferences:
375
+
376
+ ```bash
377
+ loadout alerts --json
378
+ loadout alerts --updates --json
379
+ loadout alert-pins --json
380
+ ```
381
+
382
+ If `alerts` prints an exact alert id or evidence-related replacement, exercise its
383
+ state transitions with `alert-ignore <id>`, `alert-pin <installed> <replacement>`,
384
+ `alert-pins --json`, `alert-unpin <installed>`, and `alerts --all --json`. Pinning is a
385
+ preference only; it must not install or activate anything.
386
+
387
+ Update is always preview-first:
388
+
389
+ ```bash
390
+ loadout update --json
391
+ loadout update --package <managed-package> --apply
392
+ ```
393
+
394
+ Only run the second command when the first reports a real reviewed update. Expect an
395
+ exact diff/safety plan, a snapshot on success, and refusal when new risky findings are
396
+ not acknowledged with `--approve-risk`.
397
+
398
+ ## 6. Discovery and human review queue (N/S)
399
+
400
+ ```bash
401
+ loadout discover --source hacker-news --limit 20 --min-score 20 --json
402
+ loadout discover --source github --limit 20 --queue --json
403
+ loadout discover --source all --limit 20 --queue --json
404
+ loadout review-queue --decision pending --json
405
+ ```
406
+
407
+ Expected: results contain source evidence and public repository identifiers; queueing
408
+ deduplicates leads; nothing is promoted, cloned into an agent, or installed.
409
+
410
+ For a repository printed by the queue:
411
+
412
+ ```bash
413
+ loadout review owner/repository --decision shortlisted
414
+ loadout review-queue --decision shortlisted --json
415
+ loadout review owner/repository --decision ignored
416
+ ```
417
+
418
+ Private GitHub discovery is opt-in and reads `GITHUB_TOKEN` only when `--private` is
419
+ present. Prefer a native credential reference:
420
+
421
+ ```bash
422
+ loadout discover --source github --private \
423
+ --credential-keychain <service> --queue --json
424
+ ```
425
+
426
+ Use a low-scope test token. The output and state must never contain its value.
427
+
428
+ ## 7. Static inspection, MCP, conversion, canary, and sandbox (R/S/X)
429
+
430
+ Static package analysis never executes package content:
431
+
432
+ ```bash
433
+ loadout inspect --source "$TEST_PROJECT/packages/matrix-demo" --json
434
+ loadout evaluate --source "$TEST_PROJECT/packages/matrix-demo" --json
435
+ loadout mcp --source "$TEST_PROJECT/packages/matrix-demo" --json
436
+ loadout canary --source "$TEST_PROJECT/packages/matrix-demo" \
437
+ --package matrix-demo --json
438
+ ```
439
+
440
+ Repeat `inspect`, `evaluate`, or `mcp` with `--repository owner/repository` for the
441
+ public-network path. `canary --approve` approves only a static gate when a promotion
442
+ callback exists; the CLI itself does not install the candidate.
443
+
444
+ Test conversion with an explicitly supplied static instruction:
445
+
446
+ ```bash
447
+ printf 'Review changes conservatively and report uncertainty.\n' \
448
+ > "$TEST_PROJECT/subagent.md"
449
+ loadout convert --kind subagent --target codex-skill --name matrix-reviewer \
450
+ --input "$TEST_PROJECT/subagent.md" --output "$TEST_PROJECT/converted" --json
451
+ loadout convert --kind subagent --target codex-skill --name matrix-reviewer \
452
+ --input "$TEST_PROJECT/subagent.md" --output "$TEST_PROJECT/converted" \
453
+ --yes --json
454
+ ```
455
+
456
+ Expected: preview reports preserved and dropped semantics; apply writes only beneath
457
+ the explicit output; executable behavior is never silently converted.
458
+
459
+ MCP configuration uses disposable files and previews before mutation:
460
+
461
+ ```bash
462
+ loadout mcp-config --config "$TEST_PROJECT/mcp.json" --name local-example \
463
+ --command node --arg server.js
464
+ loadout mcp-config --config "$TEST_PROJECT/mcp.json" --name local-example \
465
+ --command node --arg server.js --yes
466
+ loadout codex-mcp-config --config "$TEST_PROJECT/config.toml" \
467
+ --name remote-example --url https://example.com/mcp
468
+ loadout codex-mcp-config --config "$TEST_PROJECT/config.toml" \
469
+ --name remote-example --url https://example.com/mcp --yes
470
+ loadout mcp-recipe --json
471
+ ```
472
+
473
+ For a recipe id returned by the last command, run `mcp-recipe <id> --config
474
+ "$TEST_PROJECT/mcp-recipes.json"`, repeat with `--yes`, then use `--verify`. `--verify`
475
+ checks configuration without starting a server. `--connect --approve-risk` is an X/N
476
+ test: it launches the exact pinned artifact, performs an MCP initialize handshake,
477
+ uses only explicitly mapped `--credential NAME=env:VARIABLE` or
478
+ `NAME=keychain:SERVICE`, and stops at `--timeout`. Run it only for a recipe whose
479
+ requirements you have reviewed.
480
+
481
+ Docker sandbox execution is intentionally separate:
482
+
483
+ ```bash
484
+ loadout sandbox-run --source "$TEST_PROJECT/packages/matrix-demo" \
485
+ --image '<reviewed-image>@sha256:<digest>' \
486
+ --command node --command --version --json
487
+ loadout sandbox-run --source "$TEST_PROJECT/packages/matrix-demo" \
488
+ --image '<reviewed-image>@sha256:<digest>' \
489
+ --command node --command --version \
490
+ --approve-risk --timeout 30000 --json
491
+ ```
492
+
493
+ Expected: the first invocation refuses/only plans without approval; the approved
494
+ container has a read-only source mount, no inherited secrets, no Docker socket, no
495
+ network, and a time bound. The image may need to be pulled beforehand.
496
+
497
+ ## 8. Signing and head-to-head evidence (S)
498
+
499
+ Validate the model-free benchmark campaign and card/compare surfaces with their
500
+ deterministic automated contracts:
501
+
502
+ ```bash
503
+ npx vitest run tests/benchmark-campaign.test.ts tests/benchmark-cli.test.ts \
504
+ tests/loadout-card.test.ts tests/share-report.test.ts
505
+ ```
506
+
507
+ Expected: campaign hashes and paired order are deterministic, every retry is included
508
+ in the worst-case budget, over-budget plans are blocked, resumable metadata contains
509
+ no prompt/output/credential bytes, and aggregate comparison never invents a quality
510
+ delta. See `docs/EVALUATION_PROTOCOL_V1.md` for the campaign JSON contract. These
511
+ tests do not call a model provider and consume no provider credit.
512
+
513
+ ```bash
514
+ loadout keygen --private-key "$TEST_ROOT/private.pem" \
515
+ --public-key "$TEST_ROOT/public.pem"
516
+ loadout catalog-sign --catalog "$LOADOUT_ROOT/catalog/packages.json" \
517
+ --private-key "$TEST_ROOT/private.pem" --output "$TEST_ROOT/catalog.signed.json"
518
+ loadout catalog-verify --snapshot "$TEST_ROOT/catalog.signed.json" \
519
+ --public-key "$TEST_ROOT/public.pem"
520
+ ```
521
+
522
+ Expected: the private key is owner-only and outside the repository; verification
523
+ succeeds; changing any byte in the signed payload makes verification fail.
524
+
525
+ Preview and apply the same signed catalog inside the disposable profile:
526
+
527
+ ```bash
528
+ loadout catalog-update --source "$TEST_ROOT/catalog.signed.json" \
529
+ --public-key "$TEST_ROOT/public.pem"
530
+ loadout catalog-update --source "$TEST_ROOT/catalog.signed.json" \
531
+ --public-key "$TEST_ROOT/public.pem" --yes
532
+ loadout catalog --coverage --json
533
+ ```
534
+
535
+ Expected: preview prints an exact signed diff without mutation; apply creates a
536
+ snapshot and trusted state; the effective catalog re-verifies the stored envelope.
537
+ Repeating `--yes` refuses a replay. Test removal only in the disposable profile and
538
+ only with the separate `--allow-removals` acknowledgement.
539
+
540
+ The repository's generated feed can be triaged without network access:
541
+
542
+ ```bash
543
+ loadout candidate list --limit 5 --json
544
+ loadout candidate list --query "codex skills"
545
+ loadout capabilities --gaps --json
546
+ loadout recommend --project "$TEST_PROJECT" --agent codex --json
547
+ ```
548
+
549
+ `candidate inspect owner/repository --output ./candidate-dossier.json` is a networked
550
+ test: it performs a real public Git clone and writes a static immutable dossier to
551
+ disposable Loadout state. Review that output before exercising `candidate propose`;
552
+ proposal preview and approved proposal output never mutate the catalog.
553
+
554
+ Graphify is an explicit executable recipe rather than a broad-setup component. With
555
+ `uv` installed, exercise it only inside the disposable profile:
556
+
557
+ ```bash
558
+ loadout tool
559
+ loadout tool graphify --agents codex
560
+ loadout tool graphify --agents codex --yes --approve-risk
561
+ "$LOADOUT_HOME/runtime/graphify/bin/graphify" --version
562
+ test -f "$LOADOUT_USER_HOME/.codex/skills/graphify/SKILL.md"
563
+ loadout tool graphify --remove
564
+ loadout tool graphify --remove --yes --approve-risk
565
+ test ! -e "$LOADOUT_USER_HOME/.codex/skills/graphify"
566
+ test ! -e "$LOADOUT_HOME/runtime/graphify"
567
+ ```
568
+
569
+ Expected: preview identifies the exact wheel hash and all commands; apply reports
570
+ Graphify 0.9.17, writes only the disposable target and isolated runtime, and removal
571
+ restores the original target. The installer subprocess must not inherit API keys.
572
+
573
+ Create a deterministic workflow fixture and five declared trials per candidate. This
574
+ is harness input, not model-generated evidence, and it executes no candidate content:
575
+
576
+ ```bash
577
+ node --input-type=module <<'NODE'
578
+ import { writeFile } from "node:fs/promises";
579
+ const root = process.env.TEST_PROJECT;
580
+ const fixture = {
581
+ id: "matrix-workflow",
582
+ version: "1",
583
+ category: "workflow-adherence",
584
+ requiredActions: ["inspect", "edit", "verify"],
585
+ forbiddenActions: ["delete-unrelated"]
586
+ };
587
+ const trials = Array.from({ length: 5 }, () => [
588
+ {
589
+ candidateId: "baseline",
590
+ fixtureId: fixture.id,
591
+ observations: ["inspect", "edit", "verify"],
592
+ durationMs: 10
593
+ },
594
+ {
595
+ candidateId: "improved",
596
+ fixtureId: fixture.id,
597
+ observations: ["inspect", "edit", "verify", "report-uncertainty"],
598
+ durationMs: 10
599
+ }
600
+ ]).flat();
601
+ await writeFile(`${root}/fixture.json`, JSON.stringify(fixture, null, 2));
602
+ await writeFile(`${root}/trials.json`, JSON.stringify(trials, null, 2));
603
+ NODE
604
+ ```
605
+
606
+ Sign and inspect the resulting evidence:
607
+
608
+ ```bash
609
+ loadout head-to-head --fixture "$TEST_PROJECT/fixture.json" \
610
+ --trials "$TEST_PROJECT/trials.json" --private-key "$TEST_ROOT/private.pem" \
611
+ --output "$TEST_ROOT/evidence.json" --json
612
+ loadout alerts --evidence "$TEST_ROOT/evidence.json" \
613
+ --public-key "$TEST_ROOT/public.pem" --json
614
+ ```
615
+
616
+ The harness scores declared observations only. It never executes candidate content.
617
+ The authoritative schema, safety-failure, minimum-trial, tamper, and practical-delta
618
+ tests are also directly runnable:
619
+
620
+ ```bash
621
+ npx vitest run tests/head-to-head.test.ts tests/signing.test.ts
622
+ ```
623
+
624
+ ## 9. Credentials and model-provider verification (H/$)
625
+
626
+ This track touches the real operating-system credential store even when
627
+ `LOADOUT_HOME` is disposable. Use a unique throwaway service name and delete it.
628
+
629
+ ```bash
630
+ loadout credentials status --json
631
+ printf '%s' '<throwaway-secret>' | \
632
+ loadout credentials set loadout-matrix-test --account tester --stdin
633
+ loadout credentials check loadout-matrix-test --account tester --json
634
+ loadout credentials delete loadout-matrix-test --account tester
635
+ ```
636
+
637
+ Expected: status names the native backend; no command prints the secret; `check`
638
+ returns only presence; delete removes it. On headless Linux without Secret Service,
639
+ status should fail closed rather than use plaintext storage.
640
+
641
+ Model metadata can be tested without a key or request:
642
+
643
+ ```bash
644
+ loadout models set --id coding --provider openrouter \
645
+ --model openai/gpt-5 --credential-env OPENROUTER_API_KEY \
646
+ --agents codex --config "$TEST_PROJECT/models.json" --json
647
+ loadout models set --id coding --provider openrouter \
648
+ --model openai/gpt-5 --credential-env OPENROUTER_API_KEY \
649
+ --agents codex --config "$TEST_PROJECT/models.json" --yes --json
650
+ loadout models status --config "$TEST_PROJECT/models.json" --json
651
+ ```
652
+
653
+ The file must contain the environment-variable _name_, never its value. The paid,
654
+ authenticated test is optional:
655
+
656
+ ```bash
657
+ export OPENROUTER_API_KEY='<test key>'
658
+ loadout models verify coding --config "$TEST_PROJECT/models.json"
659
+ unset OPENROUTER_API_KEY
660
+ ```
661
+
662
+ `models verify` makes one minimal request and may consume provider credit ($). Inspect
663
+ provider billing before and after; do not run it in a loop.
664
+
665
+ ## 10. Watchers, native scheduling, completions, and loopback UI/API (X/H)
666
+
667
+ One-shot update watching is safe and networked:
668
+
669
+ ```bash
670
+ loadout watch --once --json
671
+ ```
672
+
673
+ Generate completions into disposable files and syntax-check or inspect them before
674
+ putting anything in a shell profile:
675
+
676
+ ```bash
677
+ loadout completion bash > "$TEST_ROOT/loadout.bash"
678
+ loadout completion zsh > "$TEST_ROOT/_loadout"
679
+ loadout completion fish > "$TEST_ROOT/loadout.fish"
680
+ loadout completion powershell > "$TEST_ROOT/loadout.ps1"
681
+ bash -n "$TEST_ROOT/loadout.bash"
682
+ zsh -n "$TEST_ROOT/_loadout"
683
+ ```
684
+
685
+ Native scheduling is H. The recommended path plans and applies both independent
686
+ read-only jobs as one bundle:
687
+
688
+ ```bash
689
+ loadout autopilot --time 09:00 --json
690
+ loadout autopilot --time 09:00 --yes --json
691
+ loadout autopilot --remove --yes --json
692
+ ```
693
+
694
+ Expected: the preview contains exactly an update job and a discovery job, both marked
695
+ `read-only-checks-only`, and uses a pinned `loadout-ai@<version>` npm launcher rather
696
+ than a temporary checkout path. Apply is transactional and removal removes both jobs.
697
+ Confirm removal in `launchctl` on macOS, Task Scheduler on Windows, or the user
698
+ systemd/cron facility selected on Linux. `LOADOUT_HOME` does not make the native
699
+ scheduler disposable, so never skip the remove command. The lower-level `schedule`
700
+ and `unschedule` commands remain available for job-specific control.
701
+
702
+ Loopback services are X but do not require the dashboard for normal product use:
703
+
704
+ ```bash
705
+ loadout serve --port 0
706
+ loadout dashboard --port 0
707
+ ```
708
+
709
+ Run them separately, open the printed `127.0.0.1` URL, confirm status/health/catalog
710
+ render from disposable state, and stop each with Ctrl-C. They must not bind a public
711
+ interface.
712
+
713
+ ## 11. Improvement-cycle records (S)
714
+
715
+ ```bash
716
+ loadout improve --json
717
+ loadout improve --write --output "$TEST_PROJECT/improvements" --json
718
+ ```
719
+
720
+ Copy the exact cycle id printed by the second command:
721
+
722
+ ```bash
723
+ loadout improve-feedback --id <cycle-id> --outcome partial \
724
+ --note "Disposable matrix verification" \
725
+ --directory "$TEST_PROJECT/improvements"
726
+ ```
727
+
728
+ Expected: the first command is read-only; `--write` persists a local prompt/cycle
729
+ record only; feedback requires a human-selected outcome and stores no project source
730
+ or prompt transcript.
731
+
732
+ ## 12. Cleanup and pass criteria
733
+
734
+ First verify snapshot availability and roll back any remaining disposable mutation:
735
+
736
+ ```bash
737
+ loadout rollback --list
738
+ loadout rollback
739
+ loadout list --json
740
+ loadout doctor --json
741
+ ```
742
+
743
+ Then remove the disposable root.
744
+
745
+ macOS or Linux:
746
+
747
+ ```bash
748
+ rm -rf "$TEST_ROOT"
749
+ unset TEST_ROOT TEST_PROJECT LOADOUT_USER_HOME LOADOUT_HOME LOADOUT_ROOT
750
+ unset -f loadout
751
+ ```
752
+
753
+ PowerShell:
754
+
755
+ ```powershell
756
+ Remove-Item -Recurse -Force $env:TEST_ROOT
757
+ Remove-Item Env:TEST_ROOT, Env:TEST_PROJECT, Env:LOADOUT_USER_HOME, Env:LOADOUT_HOME,
758
+ Env:LOADOUT_ROOT
759
+ Remove-Item Function:loadout
760
+ ```
761
+
762
+ The product is ready for real-profile testing only when:
763
+
764
+ 1. every automated release gate passes;
765
+ 2. dry runs and applied operations differ exactly at the documented authority flags;
766
+ 3. every managed profile or Loadout-state mutation prints a usable snapshot and
767
+ rollback restores byte-identical pre-existing content; explicit user-selected
768
+ output artifacts such as reports, dossiers, and proposals are exempt;
769
+ 4. network failures and rate limits produce actionable errors without partial agent
770
+ mutation;
771
+ 5. outputs and stored state contain no credential values;
772
+ 6. discovery never promotes, MCP inspection never launches, and comparison never
773
+ labels weak evidence as universally “best”;
774
+ 7. both native scheduled jobs are removed after testing; and
775
+ 8. the disposable test root can be deleted without finding writes in the real agent
776
+ profile.
777
+
778
+ ## Command coverage index
779
+
780
+ This index ensures no current top-level command disappears between the walkthrough
781
+ sections. Parenthesized numbers identify the track above.
782
+
783
+ - Onboarding/install: `setup`, `plan`, `install`, `demo` (4).
784
+ - Desired state/portability: `init`, `add`, `unadd`, `lock`, `sync`, `audit`,
785
+ `export`, `import` (3).
786
+ - Package/registry: `create`, `pack`, `publish`, `registry-serve`, `search` (3).
787
+ - Inventory/active set: `list`, `library`, `scan`, `status`, `doctor`, `health`,
788
+ `capabilities`, `recommend`, `profiles`, `activate`, `optimize` (2, 4).
789
+ - Lifecycle/recovery: `enable`, `disable`, `remove`, `rollback`, `update`, `watch`
790
+ (4, 5, 10).
791
+ - Evidence/freshness: `compare`, `adopt`, `alerts`, `alert-ignore`, `alert-pin`,
792
+ `alert-unpin`, `alert-pins`, `canary`, `head-to-head` (5, 7, 8).
793
+ - Discovery/review: `catalog`, `catalog-update`, `candidate`, `discover`,
794
+ `review-queue`, `review` (2, 6, 8).
795
+ - Privacy/outcomes/improvement: `report`, `share`, `outcomes`, `outcome`, `improve`,
796
+ `improve-feedback` (2, 4, 11).
797
+ - Credentials/providers/signing: `credentials`, `models`, `keygen`, `catalog-sign`,
798
+ `catalog-verify`, `catalog-update` (8, 9).
799
+ - MCP/conversion/sandbox: `mcp`, `inspect`, `evaluate`, `mcp-recipe`, `mcp-config`,
800
+ `codex-mcp-config`, `convert`, `sandbox-run` (7).
801
+ - Host/secondary surfaces: `completion`, `autopilot`, `schedule`, `unschedule`,
802
+ `serve`, `dashboard` (10).