loadout-ai 0.7.0 → 0.9.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 (108) hide show
  1. package/CHANGELOG.md +148 -1
  2. package/README.md +160 -315
  3. package/SECURITY.md +21 -1
  4. package/catalog/discovered.json +31269 -26003
  5. package/catalog/packages.json +4 -4
  6. package/dist/src/cli.js +13 -0
  7. package/dist/src/commands/agents.js +3 -1
  8. package/dist/src/commands/catalog-candidate.js +150 -0
  9. package/dist/src/commands/catalog-workflows.js +147 -0
  10. package/dist/src/commands/catalog.js +9 -367
  11. package/dist/src/commands/coordinate.js +586 -0
  12. package/dist/src/commands/coordination-discussions.js +194 -0
  13. package/dist/src/commands/coordination-sessions.js +197 -0
  14. package/dist/src/commands/inventory.js +4 -2
  15. package/dist/src/core/agents/agent-inspection.js +26 -4
  16. package/dist/src/core/{routing → agents}/model-config.js +7 -2
  17. package/dist/src/core/catalog/catalog.js +1 -0
  18. package/dist/src/core/catalog/registry.js +44 -10
  19. package/dist/src/core/catalog/safety.js +36 -7
  20. package/dist/src/core/coordination/adapters/claude-code.js +154 -0
  21. package/dist/src/core/coordination/adapters/codex.js +137 -0
  22. package/dist/src/core/coordination/adapters/types.js +64 -0
  23. package/dist/src/core/coordination/auth.js +59 -0
  24. package/dist/src/core/coordination/bridge-lease.js +79 -0
  25. package/dist/src/core/coordination/conflict-preview.js +167 -0
  26. package/dist/src/core/coordination/contract-diff.js +106 -0
  27. package/dist/src/core/coordination/coordinator.js +552 -0
  28. package/dist/src/core/coordination/crash-recovery.js +169 -0
  29. package/dist/src/core/coordination/daemon.js +667 -0
  30. package/dist/src/core/coordination/discussion.js +340 -0
  31. package/dist/src/core/coordination/events.js +161 -0
  32. package/dist/src/core/coordination/http-api.js +118 -0
  33. package/dist/src/core/coordination/interrupt-policy.js +89 -0
  34. package/dist/src/core/coordination/lock.js +110 -0
  35. package/dist/src/core/coordination/mcp-server.js +424 -0
  36. package/dist/src/core/coordination/redaction.js +85 -0
  37. package/dist/src/core/coordination/replay.js +188 -0
  38. package/dist/src/core/coordination/retention.js +128 -0
  39. package/dist/src/core/coordination/runtime.js +21 -0
  40. package/dist/src/core/coordination/session-manager.js +366 -0
  41. package/dist/src/core/coordination/watcher.js +128 -0
  42. package/dist/src/core/{routing → delegation}/first-party-skills.js +25 -13
  43. package/dist/src/core/{routing → delegation}/handoff.js +130 -63
  44. package/dist/src/core/discovery/candidate-intelligence-evidence.js +108 -0
  45. package/dist/src/core/discovery/candidate-intelligence-types.js +1 -0
  46. package/dist/src/core/discovery/candidate-intelligence-validation.js +108 -0
  47. package/dist/src/core/discovery/candidate-intelligence.js +3 -214
  48. package/dist/src/core/discovery/community.js +12 -4
  49. package/dist/src/core/discovery/github-discovery.js +6 -2
  50. package/dist/src/core/discovery/private-discovery.js +6 -2
  51. package/dist/src/core/install/reconcile.js +1 -1
  52. package/dist/src/core/install/source.js +21 -7
  53. package/dist/src/core/install/uninstall.js +39 -3
  54. package/dist/src/core/reporting/cli-guide.js +10 -6
  55. package/dist/src/core/reporting/completion.js +61 -109
  56. package/dist/src/core/reporting/doctor.js +4 -6
  57. package/dist/src/core/runtime/bounded-json.js +65 -0
  58. package/dist/src/core/runtime/github.js +30 -16
  59. package/dist/src/core/runtime/mcp-recipes.js +1 -1
  60. package/dist/src/core/workspace/active-policy.js +1 -1
  61. package/docs/CANDIDATE_INTELLIGENCE.md +9 -2
  62. package/docs/CATALOG.md +1 -1
  63. package/docs/CREDENTIAL_AND_UPDATE_POLICY.md +1 -1
  64. package/docs/DEMO_SCRIPT.md +19 -23
  65. package/docs/DISCOVERED.md +251 -250
  66. package/docs/FEATURE_TEST_MATRIX.md +10 -263
  67. package/docs/GITHUB_AUTHORIZATION.md +5 -0
  68. package/docs/LIVE_COLLABORATION.md +234 -0
  69. package/docs/PROVENANCE_AND_COMPARISON.md +1 -1
  70. package/docs/REFERENCE.md +163 -0
  71. package/docs/RELEASE_REVIEW.md +1 -2
  72. package/docs/TESTING.md +17 -1
  73. package/docs/USER_TEST_GUIDE.md +138 -3
  74. package/docs/assets/loadout-discover-activate.webp +0 -0
  75. package/docs/assets/loadout-handoff-coordinate.webp +0 -0
  76. package/docs/assets/loadout-social-preview.png +0 -0
  77. package/docs/decisions/001-coordination-jsonl-locking.md +35 -0
  78. package/docs/decisions/002-local-daemon-authentication.md +32 -0
  79. package/docs/decisions/003-bounded-agent-discussions.md +91 -0
  80. package/docs/specs/BOUNDED_AGENT_DISCUSSIONS.md +169 -0
  81. package/docs/superpowers/plans/2026-09-03-coordination-hardening.md +231 -0
  82. package/docs/superpowers/plans/2026-09-03-release-readiness.md +232 -0
  83. package/docs/superpowers/plans/2026-09-04-bounded-agent-discussions.md +121 -0
  84. package/package.json +18 -7
  85. package/skills/loadout-handoff/SKILL.md +238 -0
  86. package/MASTER_PLAN.md +0 -2207
  87. package/dist/src/core/routing/route.js +0 -539
  88. package/docs/ACTIVE_SET.md +0 -53
  89. package/docs/COMPATIBILITY_POLICY.md +0 -22
  90. package/docs/CONVERSION_AND_SANDBOX.md +0 -27
  91. package/docs/EVALUATION_PROTOCOL_V1.md +0 -300
  92. package/docs/HEAD_TO_HEAD_EVALUATION.md +0 -79
  93. package/docs/PROVIDER_CONFIGURATION.md +0 -45
  94. package/docs/README_RESEARCH.md +0 -36
  95. package/docs/REPOSITORY_STABILIZATION.md +0 -190
  96. package/docs/SAFE_UPDATE_DEMO.md +0 -25
  97. package/docs/SCHEMA_DECISIONS.md +0 -25
  98. package/docs/SUBMISSION_COPY.md +0 -90
  99. package/docs/TEAM_POLICY.md +0 -18
  100. package/docs/assets/loadout-workflow.png +0 -0
  101. package/docs/superpowers/plans/2026-07-19-relatable-readme-hero.md +0 -283
  102. package/docs/superpowers/plans/2026-07-20-loadout-readme-explainer.md +0 -116
  103. package/docs/superpowers/plans/2026-07-20-project-activation-safety.md +0 -469
  104. package/docs/superpowers/specs/2026-07-19-relatable-readme-hero-design.md +0 -80
  105. package/docs/superpowers/specs/2026-07-20-loadout-readme-explainer-design.md +0 -55
  106. package/docs/superpowers/specs/2026-07-20-project-activation-safety-design.md +0 -228
  107. package/skills/loadout-router/SKILL.md +0 -120
  108. /package/dist/src/core/{routing → agents}/credentials.js +0 -0
@@ -1,539 +0,0 @@
1
- // Sources:
2
- // Anthropic: https://allaboutclaude.com/models
3
- // OpenAI: https://benchlm.ai/openai/api-pricing
4
- // Prices as of August 2026.
5
- export const MODEL_CATALOG = [
6
- // --- Anthropic (Claude Code) ---
7
- {
8
- id: "claude-fable-5",
9
- provider: "anthropic",
10
- name: "Claude Fable 5",
11
- tier: "frontier",
12
- inputCostPer1M: 10,
13
- outputCostPer1M: 50,
14
- nativeAgents: ["claude-code"],
15
- current: true,
16
- generation: "5",
17
- },
18
- {
19
- id: "claude-opus-5",
20
- provider: "anthropic",
21
- name: "Claude Opus 5",
22
- tier: "frontier",
23
- inputCostPer1M: 5,
24
- outputCostPer1M: 25,
25
- nativeAgents: ["claude-code"],
26
- current: true,
27
- generation: "5",
28
- },
29
- {
30
- id: "claude-sonnet-5",
31
- provider: "anthropic",
32
- name: "Claude Sonnet 5",
33
- tier: "standard",
34
- inputCostPer1M: 3,
35
- outputCostPer1M: 15,
36
- nativeAgents: ["claude-code"],
37
- current: true,
38
- generation: "5",
39
- },
40
- {
41
- id: "claude-opus-4-8",
42
- provider: "anthropic",
43
- name: "Claude Opus 4.8",
44
- tier: "frontier",
45
- inputCostPer1M: 5,
46
- outputCostPer1M: 25,
47
- nativeAgents: ["claude-code"],
48
- current: false,
49
- generation: "4",
50
- },
51
- {
52
- id: "claude-opus-4-6",
53
- provider: "anthropic",
54
- name: "Claude Opus 4.6",
55
- tier: "frontier",
56
- inputCostPer1M: 5,
57
- outputCostPer1M: 25,
58
- nativeAgents: ["claude-code"],
59
- current: false,
60
- generation: "4",
61
- },
62
- {
63
- id: "claude-sonnet-4-6",
64
- provider: "anthropic",
65
- name: "Claude Sonnet 4.6",
66
- tier: "standard",
67
- inputCostPer1M: 3,
68
- outputCostPer1M: 15,
69
- nativeAgents: ["claude-code"],
70
- current: false,
71
- generation: "4",
72
- },
73
- {
74
- id: "claude-haiku-4-5",
75
- provider: "anthropic",
76
- name: "Claude Haiku 4.5",
77
- tier: "fast",
78
- inputCostPer1M: 1,
79
- outputCostPer1M: 5,
80
- nativeAgents: ["claude-code"],
81
- current: true,
82
- generation: "4",
83
- },
84
- // --- OpenAI (Codex) — GPT-5.6 family ---
85
- {
86
- id: "gpt-5.6-sol",
87
- provider: "openai",
88
- name: "GPT-5.6 Sol",
89
- tier: "frontier",
90
- inputCostPer1M: 5,
91
- outputCostPer1M: 30,
92
- nativeAgents: ["codex"],
93
- current: true,
94
- generation: "5.6",
95
- },
96
- {
97
- id: "gpt-5.6-terra",
98
- provider: "openai",
99
- name: "GPT-5.6 Terra",
100
- tier: "standard",
101
- inputCostPer1M: 2,
102
- outputCostPer1M: 12,
103
- nativeAgents: ["codex"],
104
- current: true,
105
- generation: "5.6",
106
- },
107
- {
108
- id: "gpt-5.6-luna",
109
- provider: "openai",
110
- name: "GPT-5.6 Luna",
111
- tier: "fast",
112
- inputCostPer1M: 0.2,
113
- outputCostPer1M: 1.2,
114
- nativeAgents: ["codex"],
115
- current: true,
116
- generation: "5.6",
117
- },
118
- // --- OpenAI — GPT-5.5 ---
119
- {
120
- id: "gpt-5.5",
121
- provider: "openai",
122
- name: "GPT-5.5",
123
- tier: "frontier",
124
- inputCostPer1M: 5,
125
- outputCostPer1M: 30,
126
- nativeAgents: ["codex"],
127
- current: true,
128
- generation: "5.5",
129
- },
130
- // --- OpenAI — GPT-5.4 family ---
131
- {
132
- id: "gpt-5.4",
133
- provider: "openai",
134
- name: "GPT-5.4",
135
- tier: "standard",
136
- inputCostPer1M: 2.5,
137
- outputCostPer1M: 15,
138
- nativeAgents: ["codex"],
139
- current: true,
140
- generation: "5.4",
141
- },
142
- {
143
- id: "gpt-5.4-mini",
144
- provider: "openai",
145
- name: "GPT-5.4 Mini",
146
- tier: "fast",
147
- inputCostPer1M: 0.75,
148
- outputCostPer1M: 4.5,
149
- nativeAgents: ["codex"],
150
- current: true,
151
- generation: "5.4",
152
- },
153
- // --- OpenAI — Codex-specific ---
154
- {
155
- id: "gpt-5.1-codex",
156
- provider: "openai",
157
- name: "GPT-5.1 Codex",
158
- tier: "standard",
159
- inputCostPer1M: 1.25,
160
- outputCostPer1M: 10,
161
- nativeAgents: ["codex"],
162
- current: true,
163
- generation: "5.1",
164
- },
165
- // --- OpenAI — o-series reasoning ---
166
- {
167
- id: "o3-pro",
168
- provider: "openai",
169
- name: "o3-pro",
170
- tier: "frontier",
171
- inputCostPer1M: 20,
172
- outputCostPer1M: 80,
173
- nativeAgents: ["codex"],
174
- current: true,
175
- generation: "o3",
176
- },
177
- {
178
- id: "o3",
179
- provider: "openai",
180
- name: "o3",
181
- tier: "frontier",
182
- inputCostPer1M: 2,
183
- outputCostPer1M: 8,
184
- nativeAgents: ["codex"],
185
- current: true,
186
- generation: "o3",
187
- },
188
- {
189
- id: "o4-mini",
190
- provider: "openai",
191
- name: "o4-mini",
192
- tier: "standard",
193
- inputCostPer1M: 1.1,
194
- outputCostPer1M: 4.4,
195
- nativeAgents: ["codex"],
196
- current: true,
197
- generation: "o4",
198
- },
199
- {
200
- id: "o3-mini",
201
- provider: "openai",
202
- name: "o3-mini",
203
- tier: "standard",
204
- inputCostPer1M: 1.1,
205
- outputCostPer1M: 4.4,
206
- nativeAgents: ["codex"],
207
- current: true,
208
- generation: "o3",
209
- },
210
- ];
211
- const TIER_LABELS = {
212
- frontier: "Frontier (deep reasoning)",
213
- standard: "Standard (balanced)",
214
- fast: "Fast (high throughput)",
215
- };
216
- const PHASE_CONFIG = {
217
- plan: {
218
- tier: "frontier",
219
- reason: "Architecture and decomposition need deep reasoning to avoid costly rework",
220
- agents: ["claude-code"],
221
- conserveTier: "standard",
222
- conserveTradeoff: "Slightly shallower architectural reasoning; review the plan more carefully",
223
- },
224
- implement: {
225
- tier: "standard",
226
- reason: "Implementation is high-volume; standard models score within 5% of frontier on SWE-bench",
227
- agents: ["claude-code", "codex"],
228
- conserveTier: "fast",
229
- conserveTradeoff: "May need more iterations on complex logic; fine for CRUD and boilerplate",
230
- },
231
- review: {
232
- tier: "frontier",
233
- reason: "Code review catches subtle bugs that cheaper models miss; worth the cost per-review",
234
- agents: ["claude-code", "codex"],
235
- conserveTier: "standard",
236
- conserveTradeoff: "May miss edge-case bugs; pair with a linter",
237
- },
238
- test: {
239
- tier: "fast",
240
- reason: "Test generation is pattern-heavy; fast models produce equivalent coverage",
241
- agents: ["claude-code", "codex"],
242
- },
243
- debug: {
244
- tier: "standard",
245
- reason: "Targeted debugging needs good reasoning but not frontier-level; standard balances cost and quality",
246
- agents: ["claude-code", "codex"],
247
- conserveTier: "fast",
248
- conserveTradeoff: "Works for simple bugs; complex root-cause analysis may suffer",
249
- },
250
- document: {
251
- tier: "fast",
252
- reason: "Documentation and comments are well-suited to fast models; any decent model writes docs",
253
- agents: ["claude-code", "codex"],
254
- },
255
- };
256
- const PHASE_KEYWORDS = {
257
- plan: [
258
- "plan",
259
- "design",
260
- "architect",
261
- "architecture",
262
- "rfc",
263
- "spec",
264
- "decompose",
265
- "strategy",
266
- "system design",
267
- ],
268
- implement: [
269
- "implement",
270
- "build",
271
- "code",
272
- "create",
273
- "add",
274
- "feature",
275
- "write",
276
- "develop",
277
- "make",
278
- ],
279
- review: [
280
- "review",
281
- "audit",
282
- "check",
283
- "inspect",
284
- "critique",
285
- "pr",
286
- "pull request",
287
- "diff",
288
- ],
289
- test: [
290
- "test",
291
- "spec",
292
- "coverage",
293
- "unit",
294
- "integration",
295
- "e2e",
296
- "assert",
297
- "vitest",
298
- "jest",
299
- ],
300
- debug: [
301
- "debug",
302
- "fix",
303
- "bug",
304
- "error",
305
- "crash",
306
- "broken",
307
- "investigate",
308
- "troubleshoot",
309
- "failing",
310
- ],
311
- document: [
312
- "document",
313
- "docs",
314
- "readme",
315
- "comment",
316
- "jsdoc",
317
- "changelog",
318
- "explain",
319
- "docstring",
320
- ],
321
- };
322
- // ---------------------------------------------------------------------------
323
- // Classification
324
- // ---------------------------------------------------------------------------
325
- export function classifyTask(description) {
326
- const lower = description.toLowerCase();
327
- let best = "implement";
328
- let bestScore = 0;
329
- for (const [phase, keywords] of Object.entries(PHASE_KEYWORDS)) {
330
- let score = 0;
331
- for (const kw of keywords) {
332
- if (lower.includes(kw))
333
- score++;
334
- }
335
- if (score > bestScore) {
336
- bestScore = score;
337
- best = phase;
338
- }
339
- }
340
- return best;
341
- }
342
- // ---------------------------------------------------------------------------
343
- // Model queries
344
- // ---------------------------------------------------------------------------
345
- export function modelsForTier(tier, currentOnly = true) {
346
- return MODEL_CATALOG.filter((m) => m.tier === tier && (!currentOnly || m.current));
347
- }
348
- export function modelsByProvider(provider) {
349
- return MODEL_CATALOG.filter((m) => m.provider === provider && m.current);
350
- }
351
- export function cheapestInTier(tier) {
352
- const models = modelsForTier(tier);
353
- return models.sort((a, b) => a.inputCostPer1M - b.inputCostPer1M)[0];
354
- }
355
- /**
356
- * Narrow a recommendation to the agents actually present on this machine. A
357
- * recommendation that names an agent the user has not installed is noise, so
358
- * the resolved list drives both the printed advice and the handoff command.
359
- */
360
- export function resolveAvailableAgents(suggested, installed) {
361
- const present = new Set(installed);
362
- return {
363
- available: suggested.filter((id) => present.has(id)),
364
- missing: suggested.filter((id) => !present.has(id)),
365
- };
366
- }
367
- /** Models in the recommended tier that the given agents can actually run. */
368
- export function modelsRunnableBy(models, agents) {
369
- if (!agents.length)
370
- return models;
371
- const wanted = new Set(agents);
372
- return models.filter((m) => m.nativeAgents.some((id) => wanted.has(id)));
373
- }
374
- // ---------------------------------------------------------------------------
375
- // Routing
376
- // ---------------------------------------------------------------------------
377
- export function routeTask(description, conserve = false) {
378
- return routePhase(classifyTask(description), conserve);
379
- }
380
- export function routePhase(phase, conserve = false) {
381
- const config = PHASE_CONFIG[phase];
382
- if (!config)
383
- throw new Error(`Unknown phase '${phase}'. Valid: ${Object.keys(PHASE_CONFIG).join(", ")}`);
384
- const effectiveTier = conserve && config.conserveTier ? config.conserveTier : config.tier;
385
- const models = modelsForTier(effectiveTier);
386
- const rec = {
387
- phase: phase,
388
- tier: effectiveTier,
389
- tierLabel: TIER_LABELS[effectiveTier],
390
- models,
391
- reason: conserve && config.conserveTier
392
- ? `Conserve mode: ${config.conserveTradeoff}`
393
- : config.reason,
394
- suggestedAgents: config.agents,
395
- };
396
- if (!conserve && config.conserveTier) {
397
- rec.conserveAlternative = {
398
- tier: config.conserveTier,
399
- models: modelsForTier(config.conserveTier),
400
- tradeoff: config.conserveTradeoff,
401
- };
402
- }
403
- return rec;
404
- }
405
- export function allPhaseRoutes(conserve = false) {
406
- return Object.keys(PHASE_CONFIG).map((p) => routePhase(p, conserve));
407
- }
408
- export function estimateCostSavings() {
409
- const normal = allPhaseRoutes(false);
410
- const conserved = allPhaseRoutes(true);
411
- const estimates = normal.map((r) => {
412
- const cheapest = cheapestInTier(r.tier);
413
- return {
414
- phase: r.phase,
415
- tier: r.tier,
416
- cheapestModel: cheapest?.name ?? "—",
417
- inputCost: cheapest?.inputCostPer1M ?? 0,
418
- outputCost: cheapest?.outputCostPer1M ?? 0,
419
- };
420
- });
421
- const normalTotal = estimates.reduce((s, e) => s + e.inputCost, 0);
422
- const conserveEstimates = conserved.map((r) => cheapestInTier(r.tier)?.inputCostPer1M ?? 0);
423
- const conserveTotal = conserveEstimates.reduce((s, c) => s + c, 0);
424
- return { estimates, normalTotal, conserveTotal };
425
- }
426
- /** Shell-quote a task description for the suggested handoff command. */
427
- function shellQuote(value) {
428
- return `'${value.replace(/'/g, `'\\''`)}'`;
429
- }
430
- export function formatRouteRecommendation(rec, context = {}) {
431
- // `undefined` means detection never ran, so every suggested agent stands. An
432
- // empty array means detection ran and found nothing, which must not be
433
- // silently upgraded back to the full suggestion list.
434
- const checked = context.installedAgents !== undefined;
435
- const { available, missing } = checked
436
- ? resolveAvailableAgents(rec.suggestedAgents, context.installedAgents)
437
- : { available: rec.suggestedAgents, missing: [] };
438
- // Only recommend models an available agent can actually run.
439
- const runnable = checked
440
- ? modelsRunnableBy(rec.models, available)
441
- : rec.models;
442
- const shown = (runnable.length ? runnable : rec.models).slice(0, 4);
443
- const modelNames = shown.map((m) => `${m.name} ($${m.inputCostPer1M}/$${m.outputCostPer1M})`);
444
- const lines = [
445
- `Phase: ${rec.phase}`,
446
- `Tier: ${rec.tierLabel}`,
447
- `Models: ${modelNames.join("\n ")}`,
448
- `Agents: ${available.length ? available.join(", ") : "none detected"}${missing.length ? ` (not installed: ${missing.join(", ")})` : ""}`,
449
- `Why: ${rec.reason}`,
450
- ];
451
- if (rec.conserveAlternative) {
452
- const alt = rec.conserveAlternative;
453
- const altCheapest = cheapestInTier(alt.tier);
454
- lines.push(``, `Conserve: drop to ${alt.tier} tier (${altCheapest?.name ?? "—"} at $${altCheapest?.inputCostPer1M ?? "?"}/$${altCheapest?.outputCostPer1M ?? "?"})`, ` ${alt.tradeoff}`);
455
- }
456
- // Actionable next step: hand this task to a detected agent.
457
- if (context.description && available.length) {
458
- const target = available[0];
459
- lines.push(``, `Hand off:`, ` loadout handoff send ${target} ${shellQuote(context.description)}`);
460
- if (context.handoffReady === false)
461
- lines.push(` (run \`loadout handoff init\` once to enable)`);
462
- }
463
- return lines.join("\n");
464
- }
465
- export function formatRoutingTable(conserve = false) {
466
- const routes = allPhaseRoutes(conserve);
467
- const header = `Phase Tier Cheapest model $/M in $/M out Agents`;
468
- const divider = "─".repeat(header.length);
469
- const rows = routes.map((r) => {
470
- const cheapest = cheapestInTier(r.tier);
471
- const phase = r.phase.padEnd(12);
472
- const tier = r.tier.padEnd(11);
473
- const model = (cheapest?.name ?? "—").padEnd(27);
474
- const inCost = `$${(cheapest?.inputCostPer1M ?? 0).toFixed(2)}`.padEnd(8);
475
- const outCost = `$${(cheapest?.outputCostPer1M ?? 0).toFixed(2)}`.padEnd(8);
476
- const agents = r.suggestedAgents.slice(0, 3).join(", ");
477
- return `${phase} ${tier} ${model} ${inCost} ${outCost} ${agents}`;
478
- });
479
- return [
480
- conserve
481
- ? "ROUTING TABLE (conserve mode — usage-saving tier for each phase)"
482
- : "ROUTING TABLE",
483
- "",
484
- header,
485
- divider,
486
- ...rows,
487
- ].join("\n");
488
- }
489
- export function formatCostTable() {
490
- const { estimates, normalTotal, conserveTotal } = estimateCostSavings();
491
- const header = "Phase Tier Cheapest model $/M input";
492
- const divider = "─".repeat(header.length);
493
- const rows = estimates.map((e) => {
494
- const phase = e.phase.padEnd(12);
495
- const tier = e.tier.padEnd(11);
496
- const model = e.cheapestModel.padEnd(27);
497
- return `${phase} ${tier} ${model} $${e.inputCost.toFixed(2)}`;
498
- });
499
- const savings = Math.round((1 - conserveTotal / normalTotal) * 100);
500
- return [
501
- header,
502
- divider,
503
- ...rows,
504
- divider,
505
- `Normal total: $${normalTotal.toFixed(2)}/M input across 6 phases`,
506
- `Conserve total: $${conserveTotal.toFixed(2)}/M input (${savings}% cheaper)`,
507
- "",
508
- "Prices are per-million-token list rates. Actual cost depends on prompt length.",
509
- "Use --conserve when you want to stretch remaining session quota.",
510
- ].join("\n");
511
- }
512
- export function formatModelCatalog(filter) {
513
- let models = MODEL_CATALOG;
514
- if (filter?.provider)
515
- models = models.filter((m) => m.provider === filter.provider);
516
- if (filter?.tier)
517
- models = models.filter((m) => m.tier === filter.tier);
518
- if (filter?.current !== undefined)
519
- models = models.filter((m) => m.current === filter.current);
520
- const header = "Model Provider Tier $/M in $/M out Gen Agents";
521
- const divider = "─".repeat(header.length);
522
- const rows = models.map((m) => {
523
- const name = m.name.padEnd(28);
524
- const provider = m.provider.padEnd(11);
525
- const tier = m.tier.padEnd(11);
526
- const inCost = `$${m.inputCostPer1M.toFixed(2)}`.padEnd(8);
527
- const outCost = `$${m.outputCostPer1M.toFixed(2)}`.padEnd(8);
528
- const gen = m.generation.padEnd(6);
529
- const agents = m.nativeAgents.slice(0, 3).join(", ");
530
- return `${name} ${provider} ${tier} ${inCost} ${outCost} ${gen} ${agents}`;
531
- });
532
- return [
533
- `${models.length} models${filter?.current === false ? " (including legacy)" : ""}`,
534
- "",
535
- header,
536
- divider,
537
- ...rows,
538
- ].join("\n");
539
- }
@@ -1,53 +0,0 @@
1
- # Reviewed library and active-set contract
2
-
3
- Loadout separates four facts that package managers often collapse into one word:
4
-
5
- - **cache**: `missing` or `downloaded` says whether Loadout has a private byte-for-byte
6
- library copy;
7
- - **review**: `unreviewed`, `reviewed`, or `quarantined` records evidence policy and
8
- never follows popularity alone;
9
- - **installation**: `installed` or `removed` records whether Loadout still manages the
10
- package; and
11
- - **activation**: `active` or `disabled` is per skill unit and per agent, because one
12
- skill from a collection can be visible to Claude Code while another stays disabled
13
- for Codex.
14
-
15
- Maximum Library starts reviewed skill units as `downloaded + reviewed + installed +
16
- disabled`. It can therefore hold hundreds of candidates without exposing hundreds of
17
- instructions to an agent. Power is an intentionally broader active profile; Stable is
18
- the smallest active foundation.
19
-
20
- An initial install is active and may have `cache:missing`. On the first disable,
21
- Loadout verifies that every managed file is unchanged and that no untracked file would
22
- be removed, copies the complete skill directories into its private library, verifies
23
- their hashes, and only then removes the agent-visible copies. This is the explicit
24
- migration boundary for older installations.
25
-
26
- `enable` verifies the private library hashes and refuses to overwrite any occupied
27
- agent target. It restores the exact cached bytes but keeps the library copy. Both
28
- commands are dry-run by default, can change several packages and agents under one
29
- snapshot, write a durable transaction journal before mutation, and can be reversed by
30
- `loadout rollback --snapshot <id>`.
31
-
32
- Only Loadout-managed skill directories participate. Existing unmanaged content is
33
- never silently adopted, moved, or deleted. MCP entries and other executable/configured
34
- components are deliberately outside active-set toggling; they retain their existing
35
- explicit configuration and removal workflows.
36
-
37
- A disabled package must be enabled before its tracked source can be updated. This
38
- prevents the update workflow from silently recreating agent-visible files and makes the
39
- activation transition explicit.
40
-
41
- ## Commands
42
-
43
- ```bash
44
- loadout library
45
- loadout disable <package-or-package/skill> [more-selectors] [--agents codex,claude-code]
46
- loadout disable <package-or-package/skill> --yes
47
- loadout enable <package-or-package/skill> --yes
48
- loadout activate --project . --limit 30
49
- loadout optimize --project .
50
- loadout rollback --snapshot <id>
51
- ```
52
-
53
- Machine-readable planning and results are available with `--json`.
@@ -1,22 +0,0 @@
1
- # Compatibility policy
2
-
3
- Loadout uses the same adapter matrix in inspection and installation. Each
4
- agent/component cell is one of:
5
-
6
- - **native** — Loadout writes the documented component format to the
7
- agent-owned location.
8
- - **adapted** — Loadout has a reviewed, tested mapping to an agent-specific
9
- layout or explicit config writer. The plan warns about the adaptation.
10
- - **unsupported** — Loadout does not infer a location, convert the component,
11
- or write anything.
12
-
13
- All supported platforms (Windows, macOS, and Linux) use this policy. WSL is
14
- Linux-side only: Loadout manages the POSIX home directory and never silently
15
- rewrites a Windows profile. Agent adapters are deliberately conservative:
16
- skills are native wherever a documented skill directory exists; commands,
17
- rules, and agents are native only where the adapter supplies a concrete
18
- directory; MCP is config-scoped and adapted only through its explicit JSON or
19
- Codex TOML planner; and plugin manifests are inspected/normalized but their
20
- runtime hooks are never converted or executed.
21
-
22
- Use `loadout capabilities --inspect` to view the matrix and local inventory.
@@ -1,27 +0,0 @@
1
- # Conversion loss reports and installer sandbox boundary
2
-
3
- ## Cross-agent conversion
4
-
5
- The only safe initial conversion target is a static instruction file. A source skill
6
- can be copied to an agent's documented native skill directory when that adapter marks
7
- skills `native`. For a target that supports only commands, Loadout may create one
8
- explicit command wrapper pointing at the same static instructions.
9
-
10
- Every conversion emits a loss report containing source component, target component,
11
- preserved fields, dropped fields, and the reason. Hooks, subagents, lifecycle scripts,
12
- dynamic variables, permissions, and MCP servers are never silently converted. A loss
13
- report with dropped executable behavior requires user approval and defaults to no
14
- write.
15
-
16
- ## Third-party installer threat model
17
-
18
- An installer can read secrets, write outside its target, alter shell startup files,
19
- open network connections, launch processes, or exploit the host. Therefore source
20
- repository scripts are never run on the host. Static package parsing is the normal
21
- path.
22
-
23
- If a future disposable sandbox runner is enabled, it must use a fresh filesystem,
24
- read-only source mount, no host home mount, no inherited environment variables, no
25
- Docker socket, restricted network disabled by default, bounded CPU/memory/time, and
26
- an exported file manifest. Its output is an untrusted proposal that still goes through
27
- the normal plan/safety/approval path. Failure or timeout discards the sandbox.