loadout-ai 0.5.5 → 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,39 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.5.7 - 2026-07-21
6
+
7
+ ### Changed
8
+
9
+ - Explain that `setup --mode custom` reconciles the complete selected profile, while
10
+ `install --mode custom --package <id>` adds a package without retiring the current
11
+ managed profile.
12
+ - Show package-by-package progress during complete uninstall and stop calling an
13
+ approved `uninstall --yes` operation a dry run.
14
+
15
+ ### Fixed
16
+
17
+ - Preserve pre-existing skill trees that users explicitly adopted into Loadout when
18
+ removing one package or completely uninstalling Loadout. Removal now forgets
19
+ ownership and leaves adopted bytes in place, including legacy `adopted-*` records.
20
+
21
+ ## 0.5.6 - 2026-07-21
22
+
23
+ ### Changed
24
+
25
+ - Resolve each repository's default-branch commit with a lightweight Git metadata
26
+ request before downloading files, deduplicate shared sources, and reuse exact
27
+ cached changed revisions for safety review.
28
+ - Give changed repositories a bounded 120-second review window while keeping remote
29
+ commit checks at 30 seconds, so large reviewed sources do not produce permanent
30
+ false connectivity warnings under four-way concurrency.
31
+
32
+ ### Fixed
33
+
34
+ - Complete update checks for large sources such as Scientific Agent Skills and
35
+ Awesome Copilot without weakening static diff analysis, activating disabled skills,
36
+ or treating a timed-out clone as a GitHub outage.
37
+
5
38
  ## 0.5.5 - 2026-07-21
6
39
 
7
40
  ### Changed
package/MASTER_PLAN.md CHANGED
@@ -6,12 +6,78 @@ Category: Developer Tools
6
6
  Team size: 3
7
7
  Target submission: July 21, 2026 at 5:00 PM Pacific / July 22 at 4:00 AM Dubai
8
8
 
9
- ## Current status and remaining work (July 21, 2026)
10
-
11
- This is the authoritative active list. The long phase history below is retained as
12
- an archival engineering record, not a second active plan and not a command to build
13
- every speculative system before users can test Loadout. Completed implementation
14
- plans and contributor-specific plans have been consolidated here and removed.
9
+ ## Launch finish line (authoritative, July 21, 2026)
10
+
11
+ This is the only active checklist. Everything under **Archived implementation
12
+ history** is evidence of how the product was built, not unfinished launch scope.
13
+
14
+ ### Product complete
15
+
16
+ - [x] Publish the CLI as `loadout-ai@0.5.6`; keep the product usable without cloning
17
+ this repository or providing an OpenAI/Anthropic API key.
18
+ - [x] Ship Stable, Power, Maximum, and Custom profiles with preview-first apply,
19
+ snapshots, drift protection, explicit rollback, removal, and complete uninstall.
20
+ - [x] Detect and manage skills across supported agent adapters while preserving
21
+ unrelated and unmanaged files.
22
+ - [x] Ship a 53-source pinned catalog, daily read-only discovery/update checks,
23
+ existing-skill reconciliation, and project-aware recommendation/optimization.
24
+ - [x] Credit and support the MIT Humanizer and Obsidian Skills sources. Humanizer is
25
+ available through Custom mode; Obsidian is recommended for detected vaults.
26
+ - [x] Ship three explicit MCP recipes for Playwright, Chrome DevTools, and read-only
27
+ GitHub, plus the separately reviewed Graphify runtime-tool recipe.
28
+ - [x] Remove the conflicting dashboard and make the CLI the only product surface.
29
+ - [x] Publish clear npm setup, testing, upstream attribution, trust boundaries, and a
30
+ detailed account of how Codex and GPT-5.6 were used in the README.
31
+ - [x] Pass the complete local release gate and the latest hosted CI run on `main`.
32
+ - [x] Preserve pre-existing adopted skills during removal and complete uninstall;
33
+ distinguish additive Custom installation from whole-profile Custom setup, and
34
+ show truthful progress during large approved uninstalls.
35
+
36
+ ### Final founder acceptance
37
+
38
+ - [ ] Install the exact public npm release in a fresh terminal and run the final short
39
+ path: Humanizer Custom preview/apply/scan/rollback, read-only update/discovery,
40
+ complete uninstall, and clean reinstall. Stable, Power, Maximum, project
41
+ optimization, Graphify, and both-host Playwright MCP lifecycles have already
42
+ been exercised on the founder's real profiles.
43
+ - [ ] Decide whether to rename the GitHub repository from `loadout` to `loadout-ai`.
44
+ If approved, rename it before recording and update canonical links; keep the
45
+ product name **Loadout** and npm package/CLI identity `loadout-ai` / `loadout`.
46
+ - [ ] Make the six unresolved upstream-license decisions explicit. Do not silently
47
+ convert `NOASSERTION` into a license claim because a repository is popular.
48
+
49
+ ### Submission work
50
+
51
+ - [ ] Record the real CLI demo using `docs/DEMO_SCRIPT.md`; keep it under three
52
+ minutes, include a voiceover, upload it publicly to YouTube, and verify the URL.
53
+ - [ ] Replace the README demo placeholder with the final YouTube link.
54
+ - [ ] In the voiceover, explain what Loadout does and how Codex and GPT-5.6 were used.
55
+ - [ ] Run `/feedback` in Codex, copy the resulting session ID, and enter it in Devpost.
56
+ - [ ] Confirm the repository URL is accessible to Devpost and OpenAI.
57
+ - [ ] Confirm all team invitations are accepted, select **Developer Tools**, complete
58
+ the edited Devpost description, and submit rather than leaving a draft.
59
+
60
+ ### Deliberately not part of this submission
61
+
62
+ These are not launch blockers and should not be rebuilt before submission:
63
+
64
+ - A dashboard or second frontend surface.
65
+ - Hosted accounts, GitHub OAuth, cloud sync, analytics, or enterprise administration.
66
+ - Automatic installation of newly discovered projects or arbitrary third-party
67
+ installer execution.
68
+ - A universal quality score, fabricated benchmark results, or automatic claims that
69
+ stars prove safety or usefulness.
70
+ - A production-hosted signed intelligence service, a second executable runtime tool,
71
+ speculative adapter features without user demand, or ten external user studies.
72
+ - Restoring GitHub-hosted Actions capacity before submission; the full gate can run
73
+ locally, and the latest completed `main` CI is already passing.
74
+
75
+ ## Archived current-status diary (historical, not active scope)
76
+
77
+ This section preserves the chronological implementation and founder-testing record.
78
+ Its unchecked boxes may describe older release numbers, superseded acceptance paths,
79
+ external research, or intentionally deferred work. They are not active launch tasks;
80
+ use the launch finish line above.
15
81
 
16
82
  ### Implemented product work
17
83
 
@@ -328,6 +394,14 @@ merged `codex/relatable-readme-hero` remote branch remains safe to delete after
328
394
  managed drift, and no active adopted-skill update. Release this correction
329
395
  before the remaining Graphify removal, discovery, uninstall, and reinstall
330
396
  acceptance steps.
397
+ - [x] `P18-46 [TERRA]` Eliminate the repeated large-repository timeout exposed by the
398
+ published `0.5.5` founder check. Resolve remote HEAD metadata before fetching
399
+ content, download only changed revisions that require static safety analysis,
400
+ reuse immutable cached snapshots, and allow those bounded reviews 120 seconds.
401
+ The real 40-record Maximum state now completes with 19 disabled-library
402
+ changes, 21 current packages, zero active updates, and zero unavailable checks;
403
+ both previously failing large repositories complete without changing or
404
+ activating any agent-visible skill.
331
405
 
332
406
  ### Release 0.3 lifecycle hardening
333
407
 
@@ -2127,7 +2201,7 @@ small PRs, no long-lived branches.
2127
2201
 
2128
2202
  ## 25. Immediate next tasks
2129
2203
 
2130
- Use the `Current remaining work` section at the top of this document. The next action
2131
- is founder acceptance testing with `docs/USER_TEST_GUIDE.md`; do not add a new hosted
2132
- service, provider dependency, or frontend surface until an observed user-testing issue
2133
- justifies it.
2204
+ Use **Launch finish line** at the top of this document. The next actions are the short
2205
+ founder acceptance remainder, the recorded demo, `/feedback`, and Devpost submission.
2206
+ Do not add a hosted service, provider dependency, dashboard, or speculative feature
2207
+ before the deadline.
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="./docs/assets/loadout-workflow.png" alt="Loadout workflow: choose extensions, inspect sources, preview changes, apply through a managed snapshot, and undo safely across supported AI coding agents." width="960">
2
+ <img src="./docs/assets/loadout-workflow.png" alt="Loadout discovers skills, tools, and MCP servers, keeps them in a screened library, matches an active set to each project, and manages them across AI coding agents." width="960">
3
3
  </p>
4
4
 
5
5
  <h1 align="center">Loadout</h1>
@@ -7,36 +7,50 @@
7
7
  <p align="center"><strong>Agent extensions, under control.</strong></p>
8
8
 
9
9
  <p align="center">
10
- A local CLI for inspecting, previewing, installing, and undoing managed extensions for AI coding agents.
10
+ <strong>The package manager for your AI coding setup.</strong><br>
11
+ Discover broadly. Activate the right tools for each project. Stay current without starting over.
11
12
  </p>
12
13
 
13
14
  <p align="center">
14
15
  <a href="https://github.com/VirajMishra1/loadout/actions/workflows/ci.yml"><img src="https://github.com/VirajMishra1/loadout/actions/workflows/ci.yml/badge.svg" alt="CI status"></a>
16
+ <a href="https://www.npmjs.com/package/loadout-ai"><img src="https://img.shields.io/npm/v/loadout-ai?color=cb3837&amp;logo=npm" alt="npm version"></a>
17
+ <a href="https://www.npmjs.com/package/loadout-ai"><img src="https://img.shields.io/npm/dm/loadout-ai?color=cb3837&amp;label=downloads" alt="npm downloads"></a>
18
+ <a href="https://github.com/VirajMishra1/loadout"><img src="https://img.shields.io/github/stars/VirajMishra1/loadout?style=flat&amp;logo=github" alt="GitHub stars"></a>
15
19
  <a href="./package.json"><img src="https://img.shields.io/badge/Node.js-%3E%3D20-339933?logo=node.js&amp;logoColor=white" alt="Node.js 20 or newer"></a>
16
20
  <a href="./LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License"></a>
17
21
  </p>
18
22
 
19
23
  <p align="center">
20
- <a href="#how-it-works">How it works</a> ·
21
24
  <a href="#install">Install</a> ·
25
+ <a href="#why-loadout">Why Loadout</a> ·
22
26
  <a href="#profiles">Profiles</a> ·
27
+ <a href="#catalog-and-discovery">Discover</a> ·
23
28
  <a href="#trust-and-limits">Trust</a> ·
24
- <a href="#command-reference">Commands</a> ·
25
- <a href="#development">Development</a>
29
+ <a href="#command-reference">Commands</a>
26
30
  </p>
27
31
 
28
- > [!IMPORTANT]
29
- > Installation is version-pinned so the code you test matches these docs. The commands below target `loadout-ai@0.5.5`; review the preview before every apply.
32
+ ## Install
33
+
34
+ You need Node.js 20 or newer and Git.
35
+
36
+ ```bash
37
+ npm install --global loadout-ai@0.5.7
38
+ loadout setup --mode stable
39
+ ```
40
+
41
+ The second command detects your agents and previews the 30-skill Stable loadout.
42
+ Nothing changes until you approve it. If anything goes wrong, start with the
43
+ [user test guide](./docs/USER_TEST_GUIDE.md).
30
44
 
31
45
  ## How it works
32
46
 
33
47
  **Choose -> Inspect -> Preview -> Apply -> Undo**
34
48
 
35
- 1. **Choose** a bounded profile or explicit packages.
36
- 2. **Inspect** pinned source and catalog metadata separately before setup.
37
- 3. **Preview** detected agents, aggregate repository, directory, and collision counts, warnings, skipped entries, and package IDs needing approval without changing agent target files.
38
- 4. **Apply** by rerunning with `--yes`; Loadout recomputes from current state before using a snapshot-backed transaction.
39
- 5. **Undo** the latest supported mutation with drift checks that protect later edits.
49
+ 1. **Choose** Stable, Power, Maximum, or your own package list.
50
+ 2. **Inspect** where each extension comes from and what it can do.
51
+ 3. **Preview** every planned change without changing agent files.
52
+ 4. **Apply** with `--yes`; Loadout saves a rollback snapshot first.
53
+ 5. **Undo** with `loadout rollback` if you change your mind.
40
54
 
41
55
  ### Abridged terminal transcript
42
56
 
@@ -61,47 +75,70 @@ Restored snapshot <snapshot-id>
61
75
 
62
76
  The final preview sentence above is captured CLI wording. A later `--yes` invocation recomputes the plan from pinned sources and current agent and filesystem state; it does not persist or prove identity with the earlier preview.
63
77
 
64
- Preview may populate Loadout's own cache; it leaves agent target files unchanged. Review its aggregate counts, warnings, skipped entries, and package IDs needing approval before deciding whether to run a later apply command.
78
+ Preview may fill Loadout's private download cache, but it does not change your agent
79
+ files. Review the summary and warnings before approving an apply command.
65
80
 
66
81
  ## Why Loadout
67
82
 
68
- Skills, plugins, MCP servers, and agent settings tend to accumulate one experiment at a time. Eventually it becomes hard to remember what is installed, where it came from, or how to undo it. In a game, a loadout is the deliberate set of tools chosen before a mission. Loadout brings that same discipline to AI coding agents: inspect the available equipment, choose intentionally, apply it through managed changes, and remove or roll it back later.
83
+ Loadout started with a frustrating question: **why does improving an AI coding agent
84
+ still mean opening twenty GitHub tabs?**
69
85
 
70
- - **One managed inventory.** List installed packages, inspect drift, and track what Loadout owns across configured agent paths.
71
- - **Preview by default.** Setup, updates, removal, MCP recipes, and uninstall expose a plan before their supported writes.
72
- - **Recoverable changes.** Snapshots and managed-file hashes support rollback while refusing to overwrite later user edits.
86
+ Useful skills, plugins, MCP servers, and settings arrive one experiment at a time.
87
+ Soon it is hard to remember what is installed, where it came from, whether something
88
+ better launched yesterday, or how to undo a change. The name comes from games, where
89
+ your loadout is the set of tools you choose for the mission. This does the same for AI
90
+ coding agents—without making you rebuild the setup for every agent and every project.
73
91
 
74
- ## Install
92
+ Most extension tools begin with a repo you already know. Loadout begins one step
93
+ earlier—**what is actually worth knowing?**—and stays with you after installation.
75
94
 
76
- You need Node.js 20 or newer and Git.
95
+ Loadout watches a much wider catalog than it activates. You can keep thousands of
96
+ technically screened skill copies in the disabled Maximum library, discover new projects as
97
+ they appear, and let each codebase pull a focused active set instead of dumping
98
+ everything into every prompt.
77
99
 
78
- ```bash
79
- npm install --global loadout-ai@0.5.5
80
- loadout --version
81
- loadout guide
82
- ```
100
+ | The usual workflow | The Loadout workflow |
101
+ | -------------------------------------------------------------- | ---------------------------------------------------------------- |
102
+ | Find recommendations across feeds and bookmarks | Watch one growing discovery catalog |
103
+ | Open every repo and guess whether to trust it | Inspect pinned sources, licenses, components, and risk findings |
104
+ | Copy skills separately into Claude, Codex, Cursor, and friends | Apply one reviewed selection across detected agents |
105
+ | Let every skill compete for context forever | Keep a bounded daily set or activate skills for this project |
106
+ | Hope updates do not break anything | Preview updates and protect every managed change with a snapshot |
107
+ | Manually remember what was changed | Scan, reconcile, remove, roll back, or completely uninstall |
83
108
 
84
- For source development instead:
109
+ Loadout is local, open source, and preview-first. It does not need an OpenAI or
110
+ Anthropic API key to manage skills. MCP servers and executable tools stay behind
111
+ their own explicit setup and permission steps.
85
112
 
86
- ```bash
87
- git clone https://github.com/VirajMishra1/loadout.git
88
- cd loadout
89
- npm ci
90
- npm run build
91
- npm link
92
- loadout --version
93
- ```
113
+ ### Demo
94
114
 
95
- For a first read-only preview, run:
115
+ **Demo video coming here.** The release walkthrough will show the real path—not a
116
+ mock UI: Stable install, cross-agent inventory, project optimization, update and
117
+ discovery checks, MCP setup, Graphify, rollback, and complete uninstall. The exact
118
+ under-three-minute [recording and voiceover script](./docs/DEMO_SCRIPT.md) is public.
96
119
 
97
- ```bash
98
- loadout setup --mode stable
99
- ```
100
-
101
- Nothing is installed until you explicitly approve the preview. See the [user test guide](./docs/USER_TEST_GUIDE.md) if linking, `PATH`, networking, risk approval, or rollback needs attention.
120
+ For now, the [end-to-end acceptance guide](./docs/USER_TEST_GUIDE.md) contains the same
121
+ commands you can run yourself.
102
122
 
103
123
  ## Stable workflow
104
124
 
125
+ ### Stable Boost — install the essentials and start building
126
+
127
+ Stable is the recommended daily driver: **30 selected skill directories from four
128
+ pinned public sources**, installed into each agent you choose. It covers planning,
129
+ implementation, debugging, testing, documentation, code review, frontend work,
130
+ performance, Git, shipping, and more without turning every discovered skill on.
131
+
132
+ | Included source | What Stable takes from it | GitHub |
133
+ | ---------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
134
+ | [Superpowers](https://github.com/obra/superpowers) | Planning, execution, testing, review, verification | [![GitHub stars](https://img.shields.io/github/stars/obra/superpowers?style=flat&label=stars)](https://github.com/obra/superpowers) |
135
+ | [Context7](https://github.com/upstash/context7) | Current documentation and MCP workflows | [![GitHub stars](https://img.shields.io/github/stars/upstash/context7?style=flat&label=stars)](https://github.com/upstash/context7) |
136
+ | [Addy Osmani Agent Skills](https://github.com/addyosmani/agent-skills) | Engineering, frontend, debugging, performance, docs, shipping | [![GitHub stars](https://img.shields.io/github/stars/addyosmani/agent-skills?style=flat&label=stars)](https://github.com/addyosmani/agent-skills) |
137
+ | [Agent Skills Marketplace](https://github.com/wshobson/agents) | Architecture, review, error handling, JavaScript, Python | [![GitHub stars](https://img.shields.io/github/stars/wshobson/agents?style=flat&label=stars)](https://github.com/wshobson/agents) |
138
+
139
+ Every row links directly to the upstream project. Loadout does not claim ownership
140
+ or endorsement; it pins, credits, screens, and selects from their public work.
141
+
105
142
  ```bash
106
143
  # Preview for detected agents
107
144
  loadout setup --mode stable
@@ -109,18 +146,20 @@ loadout setup --mode stable
109
146
  # Recompute from current state and apply after reviewing the preview
110
147
  loadout setup --mode stable --yes
111
148
 
112
- # Inspect managed state, then undo the latest supported mutation
113
- loadout list
114
- loadout health --explain
149
+ # Inspect managed state, then undo the install if needed
150
+ loadout status
151
+ loadout scan
115
152
  loadout rollback
116
153
  ```
117
154
 
118
- Stable currently selects 30 skill directories from four pinned, SPDX-identified, policy-selected public sources. Selection policy is evidence, not a claim that the sources are safe, trusted, human-reviewed, benchmarked, or the right choice for every user.
155
+ Stable is Loadout's strongest general starting point, not a claim that one setup is
156
+ best for every person or project. Run `loadout profiles stable --json` when you want
157
+ the machine-readable selection.
119
158
 
120
159
  ## Manage skills you already have
121
160
 
122
- Loadout can compare existing Claude, Codex, Cursor, and other detected-agent skills
123
- with complete skill trees from pinned catalog sources:
161
+ Already have skills? Loadout can compare them with exact catalog copies and manage
162
+ the ones it can identify confidently:
124
163
 
125
164
  ```bash
126
165
  # Read-only inventory and source/update comparison
@@ -134,26 +173,84 @@ loadout reconcile --yes
134
173
  loadout reconcile --replace-outdated
135
174
  ```
136
175
 
137
- Unknown or ambiguous copies remain untouched. Replacing an outdated tree is a
138
- separate `--replace-outdated --yes` transaction, may require `--approve-risk`, and
139
- creates one rollback snapshot. Once adopted or replaced, `loadout update` tracks the
140
- exact upstream repository and skill unit while preserving the agent path already in
141
- use.
176
+ Unknown or ambiguous copies stay untouched. Replacing an old copy is a separate,
177
+ previewed transaction with its own rollback snapshot. Managed copies can then be
178
+ checked by `loadout update` without moving them to a different agent path.
142
179
 
143
180
  ## Profiles
144
181
 
145
- | Profile | Scope |
146
- | ----------- | --------------------------------------------------------------------- |
147
- | **Stable** | 30 active everyday skills from four pinned sources |
148
- | **Power** | A deliberately larger active toolkit from eight pinned collections |
149
- | **Maximum** | Every screened skill in a disabled library; activate relevant subsets |
150
- | **Custom** | Only package IDs explicitly supplied by the user |
182
+ Loadout is opinionated when you want it to be and precise when you do not.
183
+
184
+ ### Power Boost a larger cross-project toolkit
185
+
186
+ Power draws a skill-level allowlist from eight major collections. The prepared set
187
+ is deduplicated and invalid units are quarantined, so the final count can be lower
188
+ than the raw allowlist. In current acceptance testing it prepared about 50 active
189
+ skills per agent.
190
+
191
+ | Included source | Focus | GitHub |
192
+ | ------------------------------------------------------------------------ | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
193
+ | [Anthropic Skills](https://github.com/anthropics/skills) | Documents, frontend, MCP building, web testing | [![GitHub stars](https://img.shields.io/github/stars/anthropics/skills?style=flat&label=stars)](https://github.com/anthropics/skills) |
194
+ | [OpenAI Skills](https://github.com/openai/skills) | CLI, docs, browser work, images, security | [![GitHub stars](https://img.shields.io/github/stars/openai/skills?style=flat&label=stars)](https://github.com/openai/skills) |
195
+ | [Vercel Agent Skills](https://github.com/vercel-labs/agent-skills) | React, web design, composition, deployment | [![GitHub stars](https://img.shields.io/github/stars/vercel-labs/agent-skills?style=flat&label=stars)](https://github.com/vercel-labs/agent-skills) |
196
+ | [Superpowers](https://github.com/obra/superpowers) | Planning, debugging, testing, collaboration | [![GitHub stars](https://img.shields.io/github/stars/obra/superpowers?style=flat&label=stars)](https://github.com/obra/superpowers) |
197
+ | [UI UX Pro Max](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill) | UI systems, slides, styling, product design | [![GitHub stars](https://img.shields.io/github/stars/nextlevelbuilder/ui-ux-pro-max-skill?style=flat&label=stars)](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill) |
198
+ | [Context7](https://github.com/upstash/context7) | Current documentation and MCP workflows | [![GitHub stars](https://img.shields.io/github/stars/upstash/context7?style=flat&label=stars)](https://github.com/upstash/context7) |
199
+ | [Agent Skills Marketplace](https://github.com/wshobson/agents) | Architecture, testing, APIs, TypeScript, Python | [![GitHub stars](https://img.shields.io/github/stars/wshobson/agents?style=flat&label=stars)](https://github.com/wshobson/agents) |
200
+ | [Awesome Copilot](https://github.com/github/awesome-copilot) | Codebase knowledge, plans, browser and security workflows | [![GitHub stars](https://img.shields.io/github/stars/github/awesome-copilot?style=flat&label=stars)](https://github.com/github/awesome-copilot) |
201
+
202
+ ```bash
203
+ loadout setup --mode power
204
+ ```
205
+
206
+ ### Maximum Library — download broadly, activate intelligently
207
+
208
+ Maximum is for explorers. It downloads every non-archived, technically screened
209
+ skill component in the catalog into Loadout's **disabled local library**. Disabled
210
+ means cached and available—not injected into agent context. Then let the current
211
+ project choose a focused active set:
212
+
213
+ ```bash
214
+ loadout setup --mode maximum
215
+ loadout recommend --project . --agent codex
216
+ loadout optimize --project . --agents codex,claude-code --limit 30
217
+ loadout optimize --project . --agents codex,claude-code --limit 30 --yes
218
+ ```
219
+
220
+ This is the difference between “install everything” and “have everything ready.”
221
+ The first overloads agents; the second gives you a large library with a small,
222
+ relevant active loadout.
223
+
224
+ ### Custom — take exact control
225
+
226
+ Use `setup` when the listed packages should become the complete managed profile for
227
+ the selected agents. Packages from the previous managed profile that are not listed
228
+ will be retired, and the preview names every retirement:
229
+
230
+ ```bash
231
+ loadout setup --mode custom --package superpowers --package context7
232
+ ```
233
+
234
+ Use `install` when you only want to add a package without replacing the current
235
+ managed profile:
236
+
237
+ ```bash
151
238
 
152
- Run `loadout profiles` to compare them and `loadout setup --mode <profile>` to preview one. Stable limits context. Power trades more context for broader always-available capability. Maximum gives you the largest library without injecting thousands of skills into every prompt; `loadout optimize --project .` chooses a relevant working set. MCP-only entries stay on a separate approval path.
239
+ # Install the reviewed Humanizer writing skill into Codex
240
+ loadout install --mode custom --package humanizer --agents codex
241
+
242
+ # Install the reviewed Obsidian skills explicitly
243
+ loadout install --mode custom --package obsidian-skills --agents codex,claude-code
244
+ ```
245
+
246
+ Run `loadout profiles` to compare every mode. MCP servers always use a separate
247
+ approval step. Obsidian skills are also proposed automatically when `recommend` or
248
+ `optimize` detects an Obsidian vault; they are not added to the universal Stable set.
153
249
 
154
250
  ## MCP integrations
155
251
 
156
- MCP servers are not silently started by Stable, Power, or Maximum. List the reviewed recipes and their credential requirements:
252
+ Profiles never start MCP servers silently. First list the available recipes and see
253
+ which ones need credentials:
157
254
 
158
255
  ```bash
159
256
  loadout mcp-recipe
@@ -171,14 +268,15 @@ loadout mcp-recipe playwright --agent claude-code
171
268
  loadout mcp-recipe playwright --agent claude-code --yes
172
269
  ```
173
270
 
174
- Configuration does not launch the server. A real bounded handshake requires the separate `--connect --approve-risk` action. Credentialed recipes accept environment or keychain references, never secret values in command output.
271
+ Configuration alone does not start the server. Test a real connection separately
272
+ with `--connect --approve-risk`. Loadout can reference credentials from environment
273
+ variables or the OS keychain without printing their values.
175
274
 
176
275
  ## Optional runtime tools
177
276
 
178
- [Graphify](https://github.com/Graphify-Labs/graphify) is available as a separate,
179
- reviewed local runtime recipe because it installs an executable as well as an agent
180
- skill. It does not need an OpenAI or Anthropic API key. Loadout previews the pinned
181
- artifact, permissions, targets, and rollback scope before doing anything:
277
+ [Graphify](https://github.com/Graphify-Labs/graphify) is an optional codebase graph
278
+ tool. It installs both a command and an agent skill, so Loadout keeps it separate from
279
+ the normal profiles. It does not require an OpenAI or Anthropic API key:
182
280
 
183
281
  ```bash
184
282
  loadout tool graphify --agents codex,claude-code
@@ -186,11 +284,38 @@ loadout tool graphify --agents codex,claude-code --yes --approve-risk
186
284
  loadout tool graphify --remove --agents codex,claude-code --yes --approve-risk
187
285
  ```
188
286
 
189
- Graphify is intentionally not hidden inside Stable, Power, or Maximum: executable
190
- tools always remain an explicit choice.
287
+ Executable tools remain an explicit choice instead of hiding inside a profile.
191
288
 
192
289
  ## Catalog and discovery
193
290
 
291
+ ### GitHub moves every day. Your loadout should not stand still.
292
+
293
+ The catalog is not a frozen “top 50” list. Loadout separates **discovery** from
294
+ **installation** so a viral repo can be noticed quickly without being trusted
295
+ blindly. Candidates enter a review queue; catalog entries are pinned and inspected;
296
+ only the bounded Stable policy gets the strongest automatic recommendation.
297
+
298
+ ```bash
299
+ # Find candidates across configured discovery sources
300
+ loadout discover --source all --queue
301
+
302
+ # Inspect the queue and one candidate before promotion
303
+ loadout review-queue
304
+ loadout candidate inspect owner/repository
305
+
306
+ # Check whether managed active or disabled-library sources changed
307
+ loadout update
308
+ loadout health --updates
309
+ ```
310
+
311
+ Daily checks are opt-in and read-only. They tell you what changed; they do not
312
+ silently rewrite your agents:
313
+
314
+ ```bash
315
+ loadout autopilot --yes
316
+ loadout autopilot --status
317
+ ```
318
+
194
319
  <!-- loadout:catalog-coverage:start -->
195
320
 
196
321
  The bundled catalog currently contains **53 credited public repositories** across **39 categories**: **34 have skill components** and **19 are MCP-only**. All 53 are technically screened and pinned; 4 sources are selected by the bounded Stable policy. See every linked source, license status, component type, and pinned commit in **[Catalog and upstream credits](./docs/CATALOG.md)**.
@@ -250,20 +375,99 @@ Configured paths and disposable filesystem lifecycle tests do not prove that nat
250
375
 
251
376
  ## Command reference
252
377
 
253
- | Job | Command |
254
- | ---------------------------------- | ------------------------------------------- |
255
- | Guided read-only path | `loadout guide` |
256
- | Preview or apply a profile | `loadout setup --mode stable [--yes]` |
257
- | List and inspect managed state | `loadout list`; `loadout health --explain` |
258
- | Compare/manage existing skills | `loadout reconcile [--refresh]` |
259
- | Browse or search | `loadout catalog`; `loadout search <words>` |
260
- | Recommend for a project | `loadout recommend --project .` |
261
- | Preview or apply updates | `loadout update [--yes]` |
262
- | Undo the latest supported mutation | `loadout rollback` |
263
- | Remove one managed package | `loadout remove <package>` |
264
- | Preview complete removal | `loadout uninstall` |
265
- | List reviewed MCP integrations | `loadout mcp-recipe` |
266
- | Discover the full surface | `loadout --help`; `loadout advanced` |
378
+ Start at the top and stop whenever Loadout does everything you need.
379
+
380
+ | Priority | What it does | Command |
381
+ | -------: | --------------------------------------------------------------- | ------------------------------------------------------------------ |
382
+ | 1 | Opens the beginner-friendly guided path | `loadout guide` |
383
+ | 2 | Previews the recommended 30-skill daily setup | `loadout setup --mode stable` |
384
+ | 3 | Previews the broader Power setup | `loadout setup --mode power` |
385
+ | 4 | Downloads the broad screened library, disabled by default | `loadout setup --mode maximum` |
386
+ | 5 | Shows Loadout-managed packages and active skills | `loadout status`; `loadout library` |
387
+ | 6 | Inventories skills across detected agents without changing them | `loadout scan` |
388
+ | 7 | Explains what fits the current repository | `loadout recommend --project . --agent codex` |
389
+ | 8 | Previews a bounded project-specific active set | `loadout optimize --project . --limit 30` |
390
+ | 9 | Compares existing skills with reviewed catalog copies | `loadout reconcile --refresh` |
391
+ | 10 | Checks managed active and disabled-library sources for changes | `loadout update` |
392
+ | 11 | Finds newly launched or newly popular candidates | `loadout discover --source all --queue` |
393
+ | 12 | Shows candidates waiting for deeper review | `loadout review-queue` |
394
+ | 13 | Lists MCP recipes and credential needs | `loadout mcp-recipe`; `loadout mcp-recipe --credential-free` |
395
+ | 14 | Previews an MCP configuration | `loadout mcp-recipe playwright --agent codex` |
396
+ | 15 | Lists and installs isolated runtime tools such as Graphify | `loadout tool`; `loadout tool graphify --agents codex,claude-code` |
397
+ | 16 | Lists snapshots or restores the latest managed change | `loadout rollback --list`; `loadout rollback` |
398
+ | 17 | Previews removal of one managed package | `loadout remove <package-id>` |
399
+ | 18 | Previews complete removal of Loadout-managed state | `loadout uninstall` |
400
+ | 19 | Enables read-only daily discovery and update checks | `loadout autopilot --yes` |
401
+ | 20 | Shows the complete CLI | `loadout --help`; `loadout advanced` |
402
+
403
+ Most mutating commands are dry runs first. After reading the preview, add `--yes` to
404
+ apply. Commands with executable or connection risk require the additional approval
405
+ shown in their output.
406
+
407
+ ## Built with Codex and GPT-5.6
408
+
409
+ Loadout was built during OpenAI Build Week by a three-person team working with Codex
410
+ and GPT-5.6. Codex was not a chat box bolted onto the finished project. It was the
411
+ engineering environment we used to plan, build, test, and repeatedly challenge the
412
+ product while it was taking shape.
413
+
414
+ ### From a broad idea to a working product
415
+
416
+ The starting idea was simple: one install that gives every coding agent the best
417
+ extensions on GitHub. The difficult part was everything hidden inside that sentence.
418
+ What counts as “best”? How much should stay active? What happens to skills a user
419
+ already has? How do you update a repository without silently trusting new code? How
420
+ do you undo changes across several agents?
421
+
422
+ We used GPT-5.6 through Codex for the repo-wide reasoning behind those decisions.
423
+ Together, we turned the idea into three distinct modes: a bounded Stable daily
424
+ driver, a larger Power setup, and a Maximum library that keeps broad optionality
425
+ without loading thousands of skills into every prompt.
426
+
427
+ | Part of the build | How we used Codex and GPT-5.6 | What made it into Loadout |
428
+ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
429
+ | Product planning | Broke the original idea into testable user journeys and challenged unsafe assumptions | Stable, Power, Maximum, Custom, project optimization, discovery, updates, and complete uninstall |
430
+ | Architecture | Traced how catalogs, adapters, agent directories, manifests, and snapshots affect one another | A local TypeScript CLI with a shared catalog, 12 agent adapters, and snapshot-backed transactions |
431
+ | Ecosystem research | Compared repositories, checked source layouts and licenses, and separated popularity from evidence | 53 pinned catalog sources plus a discovery snapshot watching 240 repositories |
432
+ | Implementation | Wrote and refactored CLI commands, schemas, source fetchers, installers, active-set logic, and MCP configuration | The published `loadout-ai` package and the commands documented above |
433
+ | Safety work | Looked for scripts, hooks, binaries, credential references, target collisions, stale previews, and external edits | Preview-first changes, quarantined skill units, explicit risk approval, drift protection, and rollback |
434
+ | Testing | Generated adversarial cases, reproduced failures from real terminal sessions, and converted them into regression tests | 620 passing tests, CLI and README end-to-end flows, package smoke tests, and a 1,000-skill performance gate |
435
+ | Team integration | Audited teammate branches, compared them with `main`, prepared focused pull requests, and checked what was actually complete | One public history instead of three disconnected prototypes |
436
+ | Release work | Verified npm contents, version behavior, GitHub metadata, documentation claims, and public CI | A public npm package, credited upstream catalog, release evidence, and a reproducible verification command |
437
+
438
+ ### Real testing changed the code
439
+
440
+ Codex was most useful when the neat plan met a messy laptop. A few examples:
441
+
442
+ - A Graphify install appeared in Claude Code but vanished from Codex inventory
443
+ because the generated runtime skill and the normal skill scanner used different
444
+ Codex paths. The scan now recognizes managed runtime-tool skills explicitly.
445
+ - Update checks repeatedly timed out on large repositories. We measured the real
446
+ clone cost, changed the update path to check remote commit metadata first, and only
447
+ fetch a full snapshot when a pinned source actually changed.
448
+ - Existing unmanaged skills could occupy the same target as a Stable install.
449
+ Instead of overwriting them, Loadout now stops, scans, compares, and offers a
450
+ separate reconciliation path for exact or unambiguous matches.
451
+ - ChatGPT and Claude subscriptions were easy to confuse with separately billed API
452
+ access. Setup now asks about API access explicitly, while credentialed MCP servers
453
+ remain separate from automatic skill installation.
454
+
455
+ Those fixes came from a loop we repeated throughout the week: run the real command,
456
+ paste the exact output into Codex, trace the behavior through the codebase, write a
457
+ regression test, fix the smallest responsible layer, and run the full release gate.
458
+
459
+ ### What the team owned
460
+
461
+ The humans chose the product direction, selected the tradeoffs, reviewed upstream
462
+ projects, tested Loadout on real Codex and Claude Code profiles, approved risky
463
+ operations, and made every release decision. GPT-5.6 helped with high-context design,
464
+ debugging, and review; Codex handled the implementation loop and verification tools.
465
+ Neither replaced human judgment about what should be installed on someone else's
466
+ machine.
467
+
468
+ Loadout itself does **not** call GPT-5.6 and does not require an OpenAI API key to
469
+ manage skills. Codex and GPT-5.6 helped build the tool; they are not a hidden runtime
470
+ dependency.
267
471
 
268
472
  ## Development
269
473
 
@@ -291,8 +495,7 @@ The repository's mixed README product-flow test uses an isolated build, disposab
291
495
  - [Daily discovery snapshot](./docs/DISCOVERED.md)
292
496
  - [Candidate inspection and promotion](./docs/CANDIDATE_INTELLIGENCE.md)
293
497
  - [Credential and update policy](./docs/CREDENTIAL_AND_UPDATE_POLICY.md)
294
- - [Repository stabilization record](./docs/REPOSITORY_STABILIZATION.md)
295
- - [Engineering plan](./MASTER_PLAN.md) and [changelog](./CHANGELOG.md)
498
+ - [Changelog](./CHANGELOG.md)
296
499
 
297
500
  ## Contributing, security, and attribution
298
501
 
package/dist/src/cli.js CHANGED
@@ -264,7 +264,7 @@ async function runSetup(options) {
264
264
  reader?.close();
265
265
  }
266
266
  }
267
- const LOADOUT_VERSION = "0.5.5";
267
+ const LOADOUT_VERSION = "0.5.7";
268
268
  function durableSchedulerLauncher() {
269
269
  return [
270
270
  join(dirname(process.execPath), process.platform === "win32" ? "npx.cmd" : "npx"),
@@ -909,7 +909,7 @@ program
909
909
  .option("--agents <ids>", "limit explained scores to selected agent ids")
910
910
  .action(async (options) => {
911
911
  if (options.updates && !options.json)
912
- console.error("Checking managed repositories (4 at a time, 30s per network operation)…");
912
+ console.error("Checking repository commits (4 at a time; changed sources may take up to 120s for safety review)…");
913
913
  const report = await buildHealthReport({
914
914
  updates: options.updates
915
915
  ? () => buildUpdatePlan(undefined, {
@@ -1020,11 +1020,12 @@ program
1020
1020
  .option("--remove-cli", "also uninstall the global loadout-ai npm command")
1021
1021
  .action(async (options) => {
1022
1022
  const plan = await buildUninstallPlan();
1023
- console.log(formatUninstallPlan(plan));
1023
+ console.log(formatUninstallPlan(plan, { applying: Boolean(options.yes) }));
1024
1024
  if (!options.yes)
1025
1025
  return;
1026
1026
  const result = await applyUninstall(plan, undefined, {
1027
1027
  force: options.force,
1028
+ onProgress: (message) => console.log(`→ ${message}`),
1028
1029
  });
1029
1030
  console.log(`Removed ${result.removedPackages} managed package(s), ${result.removedRuntimeTools} runtime tool(s), daily jobs, cache, library, and Loadout state.`);
1030
1031
  if (options.removeCli) {
@@ -2857,7 +2858,7 @@ program
2857
2858
  profile = await evaluateInstalledProfile(catalog);
2858
2859
  }
2859
2860
  if (!options.json)
2860
- console.error("Checking managed repositories (4 at a time, 30s per network operation)…");
2861
+ console.error("Checking repository commits (4 at a time; changed sources may take up to 120s for safety review)…");
2861
2862
  let plans = await buildUpdatePlan(undefined, {
2862
2863
  packageId: options.package,
2863
2864
  onProgress: options.json
@@ -195,6 +195,7 @@ export async function applySkillAdoption(plan, options = {}) {
195
195
  }, async (freshPlan, snapshot) => {
196
196
  await options.beforeRecord?.();
197
197
  await recordInstall(freshPlan.installPlan, snapshot.id, {
198
+ ownershipOrigin: "adopted",
198
199
  ...(freshPlan.repository ? { repository: freshPlan.repository } : {}),
199
200
  ...(freshPlan.resolvedCommit
200
201
  ? { resolvedCommit: freshPlan.resolvedCommit }
@@ -31,6 +31,10 @@ snapshot before changing managed files. Recover with: loadout rollback
31
31
  Reconcile is also read-only unless you add --yes. Exact matches can be managed
32
32
  without rewriting them; outdated replacements remain a separate explicit choice.
33
33
 
34
+ Setup reconciles the complete selected profile. To add one catalog package without
35
+ retiring the current managed profile, use:
36
+ loadout install --mode custom --package <id>
37
+
34
38
  Nothing above changes your agents. For the full maintainer/tooling surface, run:
35
39
  loadout advanced
36
40
  `.trim();
@@ -237,6 +237,7 @@ export async function applyReconcilePlan(plan, options = {}) {
237
237
  const entries = selected.map((item) => ({
238
238
  plan: installPlanFor(item, item.status === "outdated"),
239
239
  metadata: {
240
+ ownershipOrigin: "adopted",
240
241
  repository: item.candidate.repository,
241
242
  resolvedCommit: item.candidate.commit,
242
243
  reviewed: true,
@@ -11,6 +11,12 @@ export async function planRemove(packageId) {
11
11
  const trackedMcp = (state.mcpInstalls ?? []).filter((entry) => entry.packageId === packageId);
12
12
  if (!record && !trackedMcp.length)
13
13
  throw new Error(`Package is not managed by Loadout: ${packageId}`);
14
+ // Older releases encoded reconciled/adopted ownership in the generated id.
15
+ // Preserve that compatibility so upgrading Loadout protects already-adopted
16
+ // user content even before the new explicit state field has been written.
17
+ const preserveFiles = Boolean(record &&
18
+ (record.ownershipOrigin === "adopted" ||
19
+ record.packageId.startsWith("adopted-")));
14
20
  const files = await Promise.all((record?.files ?? []).map(async (file) => {
15
21
  const managedPath = managedFileReadPath(packageId, file.path, state.activations ?? []);
16
22
  try {
@@ -28,7 +34,9 @@ export async function planRemove(packageId) {
28
34
  return { path: managedPath, status: "missing" };
29
35
  }
30
36
  }));
31
- const modified = files.filter((file) => file.status === "modified");
37
+ const modified = preserveFiles
38
+ ? []
39
+ : files.filter((file) => file.status === "modified");
32
40
  const mcpServers = await Promise.all(trackedMcp.map(async (entry) => {
33
41
  try {
34
42
  if (entry.configFormat === "codex-toml") {
@@ -76,6 +84,11 @@ export async function planRemove(packageId) {
76
84
  }));
77
85
  const modifiedMcp = mcpServers.filter((entry) => entry.status === "modified");
78
86
  const warnings = [
87
+ ...(preserveFiles
88
+ ? [
89
+ "This package adopted pre-existing files; removal will forget Loadout ownership and preserve those files in place.",
90
+ ]
91
+ : []),
79
92
  ...(modified.length
80
93
  ? [`${modified.length} managed file(s) were modified outside Loadout.`]
81
94
  : []),
@@ -89,6 +102,7 @@ export async function planRemove(packageId) {
89
102
  warnings.push("Removal is blocked unless --force is used.");
90
103
  return {
91
104
  packageId,
105
+ preserveFiles,
92
106
  files,
93
107
  mcpServers,
94
108
  blocked: modified.length > 0 || modifiedMcp.length > 0,
@@ -103,17 +117,18 @@ export async function applyRemove(plan, options = {}) {
103
117
  const existing = fresh.files
104
118
  .filter((file) => file.status !== "missing")
105
119
  .map((file) => file.path);
120
+ const removableFiles = fresh.preserveFiles ? [] : existing;
106
121
  const configPaths = [
107
122
  ...new Set(fresh.mcpServers
108
123
  .filter((entry) => entry.status !== "missing")
109
124
  .map((entry) => entry.configPath)),
110
125
  ];
111
126
  return {
112
- targets: [...existing, ...configPaths, installStatePath()],
113
- value: { fresh, existing, configPaths },
127
+ targets: [...removableFiles, ...configPaths, installStatePath()],
128
+ value: { fresh, removableFiles, configPaths },
114
129
  };
115
- }, async ({ fresh, existing, configPaths }) => {
116
- for (const file of existing)
130
+ }, async ({ fresh, removableFiles, configPaths }) => {
131
+ for (const file of removableFiles)
117
132
  await rm(file, { force: true });
118
133
  for (const configPath of configPaths) {
119
134
  const relevant = fresh.mcpServers.filter((entry) => entry.configPath === configPath && entry.status !== "missing");
@@ -143,7 +158,9 @@ export async function applyRemove(plan, options = {}) {
143
158
  proposed: { ...current, mcpServers: servers },
144
159
  });
145
160
  }
146
- await forgetInstall(plan.packageId);
161
+ await forgetInstall(plan.packageId, {
162
+ dropActivations: fresh.preserveFiles,
163
+ });
147
164
  }, { label: `remove ${plan.packageId}` });
148
165
  return applied.snapshotId;
149
166
  }
@@ -144,6 +144,36 @@ export function normalizeRepository(input) {
144
144
  }
145
145
  return value;
146
146
  }
147
+ export function parseRepositoryHead(repository, output) {
148
+ const commit = output
149
+ .split(/\r?\n/)
150
+ .map((line) => line.split(/\s+/))
151
+ .find((parts) => parts[1] === "HEAD" && /^[0-9a-f]{40}$/i.test(parts[0]))?.[0];
152
+ if (!commit)
153
+ throw new Error(`Git returned an invalid default-branch HEAD for ${repository}`);
154
+ return commit;
155
+ }
156
+ /** Resolve the public default-branch commit without downloading repository files. */
157
+ export async function resolveRepositoryHead(input, options = {}) {
158
+ const repository = normalizeRepository(input);
159
+ const gitEnvironment = await isolatedGitEnvironment(loadoutHome());
160
+ const url = `https://github.com/${repository}.git`;
161
+ try {
162
+ const { stdout } = await execFileAsync("git", ["ls-remote", "--symref", "--", url, "HEAD"], {
163
+ maxBuffer: 1024 * 1024,
164
+ timeout: options.timeoutMs,
165
+ env: gitEnvironment,
166
+ });
167
+ return {
168
+ repository,
169
+ commit: parseRepositoryHead(repository, stdout),
170
+ };
171
+ }
172
+ catch (error) {
173
+ const message = error instanceof Error ? error.message : String(error);
174
+ throw new Error(`Could not resolve ${repository}: ${message}`);
175
+ }
176
+ }
147
177
  function normalizeRef(ref) {
148
178
  if (!/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(ref) ||
149
179
  ref.includes("..") ||
@@ -145,6 +145,9 @@ async function createInstallRecord(plan, snapshotId, metadata = {}) {
145
145
  const files = (await Promise.all([...new Set(plan.files.map((file) => file.target))].map(hashDirectory))).flat();
146
146
  return {
147
147
  packageId: plan.packageId,
148
+ ...(metadata.ownershipOrigin
149
+ ? { ownershipOrigin: metadata.ownershipOrigin }
150
+ : {}),
148
151
  ...(metadata.repository ? { repository: metadata.repository } : {}),
149
152
  ...(metadata.resolvedCommit
150
153
  ? { resolvedCommit: metadata.resolvedCommit }
@@ -311,7 +314,7 @@ export async function recordMcpInstall(record) {
311
314
  ];
312
315
  await writeInstallState(state);
313
316
  }
314
- export async function forgetInstall(packageId) {
317
+ export async function forgetInstall(packageId, options = {}) {
315
318
  const state = await readInstallState();
316
319
  const installs = state.installs.filter((entry) => entry.packageId !== packageId);
317
320
  const mcpInstalls = (state.mcpInstalls ?? []).filter((entry) => entry.packageId !== packageId);
@@ -323,13 +326,15 @@ export async function forgetInstall(packageId) {
323
326
  installs,
324
327
  ...(state.profile ? { profile: state.profile } : {}),
325
328
  mcpInstalls,
326
- activations: (state.activations ?? []).map((entry) => entry.packageId === packageId
327
- ? {
328
- ...entry,
329
- installationState: "removed",
330
- activationState: "disabled",
331
- updatedAt: new Date().toISOString(),
332
- }
333
- : entry),
329
+ activations: options.dropActivations
330
+ ? (state.activations ?? []).filter((entry) => entry.packageId !== packageId)
331
+ : (state.activations ?? []).map((entry) => entry.packageId === packageId
332
+ ? {
333
+ ...entry,
334
+ installationState: "removed",
335
+ activationState: "disabled",
336
+ updatedAt: new Date().toISOString(),
337
+ }
338
+ : entry),
334
339
  });
335
340
  }
@@ -85,19 +85,25 @@ export async function applyUninstall(plan, dependencies = {}, options = {}) {
85
85
  if (fresh.blocked && !options.force)
86
86
  throw new Error(`Complete uninstall is blocked because managed files were modified. Review them, or re-run with --force. ${fresh.warnings.join(" ")}`);
87
87
  for (const id of fresh.runtimeTools) {
88
+ options.onProgress?.(`Removing runtime tool: ${id}`);
88
89
  const runtimePlan = await planRuntimeTool(id, {
89
90
  action: "remove",
90
91
  stateHome: fresh.stateHome,
91
92
  });
92
93
  await applyRuntimeToolPlan(runtimePlan, { approveRisk: true });
93
94
  }
94
- for (const packagePlan of fresh.packages)
95
+ for (const [index, packagePlan] of fresh.packages.entries()) {
96
+ options.onProgress?.(`${packagePlan.preserveFiles ? "Forgetting adopted ownership" : "Removing managed package"} [${index + 1}/${fresh.packages.length}]: ${packagePlan.packageId}`);
95
97
  await applyRemove(packagePlan, { force: options.force });
98
+ }
96
99
  await removeEmptyManagedDirectories(fresh.packages);
97
- if (fresh.schedulers.length)
100
+ if (fresh.schedulers.length) {
101
+ options.onProgress?.("Removing daily read-only schedules");
98
102
  await (dependencies.unschedule
99
103
  ? dependencies.unschedule(fresh.schedulers)
100
104
  : applyNativeSchedulerBundle(fresh.schedulers));
105
+ }
106
+ options.onProgress?.("Deleting Loadout cache, library, history, and state");
101
107
  await rm(fresh.stateHome, { recursive: true, force: true });
102
108
  return {
103
109
  removedPackages: fresh.packages.length,
@@ -112,7 +118,7 @@ export async function uninstallGlobalCli() {
112
118
  windowsHide: true,
113
119
  });
114
120
  }
115
- export function formatUninstallPlan(plan) {
121
+ export function formatUninstallPlan(plan, options = {}) {
116
122
  const modifiedPaths = plan.packages.flatMap((entry) => entry.files
117
123
  .filter((file) => file.status === "modified")
118
124
  .map((file) => file.path));
@@ -137,7 +143,13 @@ export function formatUninstallPlan(plan) {
137
143
  "",
138
144
  ...plan.warnings.map((warning) => `Warning: ${warning}`),
139
145
  "",
140
- "Dry run only. Re-run with `loadout uninstall --yes` to remove Loadout-managed data.",
141
- "Add `--remove-cli` to also uninstall the global npm command.",
146
+ ...(options.applying
147
+ ? [
148
+ "Approved removal is starting. Large libraries can take several minutes; progress will be shown below.",
149
+ ]
150
+ : [
151
+ "Dry run only. Re-run with `loadout uninstall --yes` to remove Loadout-managed data.",
152
+ "Add `--remove-cli` to also uninstall the global npm command.",
153
+ ]),
142
154
  ].join("\n");
143
155
  }
@@ -1,6 +1,6 @@
1
1
  import { mkdir, writeFile } from "node:fs/promises";
2
2
  import { basename, join } from "node:path";
3
- import { fetchRepositorySnapshot } from "./source.js";
3
+ import { fetchRepositorySnapshot, resolveRepositoryHead } from "./source.js";
4
4
  import { repositoryCachePath } from "./source.js";
5
5
  import { diffRepositorySnapshots } from "./diff.js";
6
6
  import { hashDirectory, readInstallState } from "./state.js";
@@ -85,21 +85,39 @@ async function analyzeManagedUpdate(oldRoot, newRoot, unitIds) {
85
85
  };
86
86
  }
87
87
  /** Builds a read-only update plan from persisted installs and live GitHub snapshots. */
88
- export async function buildUpdatePlan(resolver = async (repository) => fetchRepositorySnapshot(repository, { timeoutMs: 30_000 }), options = {}) {
88
+ export async function buildUpdatePlan(resolver, options = {}) {
89
89
  const state = await readInstallState();
90
90
  const records = options.packageId
91
91
  ? state.installs.filter((record) => record.packageId === options.packageId)
92
92
  : state.installs;
93
93
  const results = new Array(records.length);
94
+ const lightweightResolver = resolver ??
95
+ options.resolveHead ??
96
+ ((repository) => resolveRepositoryHead(repository, { timeoutMs: 30_000 }));
94
97
  const resolutions = new Map();
95
98
  const resolveOnce = (repository) => {
96
99
  const existing = resolutions.get(repository);
97
100
  if (existing)
98
101
  return existing;
99
- const pending = resolver(repository);
102
+ const pending = lightweightResolver(repository);
100
103
  resolutions.set(repository, pending);
101
104
  return pending;
102
105
  };
106
+ const changedSnapshots = new Map();
107
+ const fetchChangedOnce = (repository, commit) => {
108
+ const key = `${repository}\0${commit.toLowerCase()}`;
109
+ const existing = changedSnapshots.get(key);
110
+ if (existing)
111
+ return existing;
112
+ const pending = options.fetchChangedSnapshot
113
+ ? options.fetchChangedSnapshot(repository)
114
+ : fetchRepositorySnapshot(repository, {
115
+ ref: commit,
116
+ timeoutMs: 120_000,
117
+ });
118
+ changedSnapshots.set(key, pending);
119
+ return pending;
120
+ };
103
121
  let cursor = 0;
104
122
  let completed = 0;
105
123
  const workers = Array.from({
@@ -139,9 +157,16 @@ export async function buildUpdatePlan(resolver = async (repository) => fetchRepo
139
157
  let diff;
140
158
  let safetyFindings;
141
159
  let approvalRequired = false;
142
- if (!same && current.path) {
160
+ let currentPath = current.path;
161
+ if (!same && !currentPath && !resolver) {
162
+ const fetched = await fetchChangedOnce(record.repository, current.commit);
163
+ if (fetched.commit.toLowerCase() !== current.commit.toLowerCase())
164
+ throw new Error(`Resolved ${current.commit}, but fetched ${fetched.commit} for safety review`);
165
+ currentPath = fetched.path;
166
+ }
167
+ if (!same && currentPath) {
143
168
  const oldPath = repositoryCachePath(record.repository, record.resolvedCommit);
144
- const analysis = await analyzeManagedUpdate(oldPath, current.path, managedUnitIds(state, record.packageId));
169
+ const analysis = await analyzeManagedUpdate(oldPath, currentPath, managedUnitIds(state, record.packageId));
145
170
  diff = analysis.diff;
146
171
  safetyFindings = analysis.safetyFindings;
147
172
  approvalRequired = analysis.approvalRequired;
@@ -269,6 +269,7 @@ const fileHashSchema = z.object({ path: text, sha256 });
269
269
  export const installRecordSchema = z
270
270
  .object({
271
271
  packageId: text,
272
+ ownershipOrigin: z.enum(["installed", "adopted"]).optional(),
272
273
  repository: optionalText,
273
274
  resolvedCommit: optionalText,
274
275
  targetAgents: z.array(agentIdSchema),
@@ -0,0 +1,155 @@
1
+ # Loadout demo and voiceover
2
+
3
+ Target length: **2:35–2:50**. Record the real CLI, cut fetch waits and typing, and do
4
+ not show the retired dashboard. The final YouTube upload must be public.
5
+
6
+ ## Before recording
7
+
8
+ 1. Close terminals that show tokens, private paths you do not want public, or unrelated
9
+ work. Increase terminal font size and use a window about 120 columns wide.
10
+ 2. Confirm the release and product health:
11
+
12
+ ```bash
13
+ npm install --global loadout-ai@0.5.7
14
+ hash -r
15
+ loadout --version
16
+ loadout health
17
+ ```
18
+
19
+ 3. Finish the remaining founder acceptance path before recording. Keep the useful
20
+ successful output in terminal history, but start the recording from a clean prompt.
21
+ 4. Rehearse the voiceover once. Use macOS Screenshot (`Shift-Command-5`) with your
22
+ microphone, OBS, or another recorder. Record at normal speed; speed the final cut
23
+ to 1.1x only if necessary.
24
+
25
+ ## Shot list and exact narration
26
+
27
+ ### 0:00–0:15 — the problem
28
+
29
+ **Screen:** README hero, then a terminal showing `loadout --version`.
30
+
31
+ **Say:**
32
+
33
+ > AI coding extensions are scattered across GitHub. You find a skill on X, an MCP
34
+ > server on Reddit, copy it into one agent, and later have no idea where it came from
35
+ > or how to undo it. I built Loadout: one local CLI to discover, inspect, install,
36
+ > update, and roll back agent extensions across Codex, Claude Code, and other agents.
37
+
38
+ ### 0:15–0:50 — one safe install
39
+
40
+ **Screen:** Run the preview, then apply. Cut the fetch wait, not the result.
41
+
42
+ ```bash
43
+ loadout setup --mode stable --agents codex,claude-code --api-access none
44
+ loadout setup --mode stable --agents codex,claude-code --api-access none --yes
45
+ ```
46
+
47
+ **Say:**
48
+
49
+ > Stable selects thirty useful skill directories per agent from four pinned public
50
+ > sources. The first run is a preview: it shows the sources, targets, credentials, and
51
+ > safety findings without changing agent files. When I approve it, Loadout applies one
52
+ > transaction and gives me a rollback snapshot. My ChatGPT and Claude subscriptions
53
+ > are not treated as API keys, and normal skill setup does not need one.
54
+
55
+ ### 0:50–1:12 — see what changed and undo it
56
+
57
+ **Screen:**
58
+
59
+ ```bash
60
+ loadout scan
61
+ loadout status
62
+ loadout rollback --list
63
+ loadout rollback --snapshot <stable-snapshot-id>
64
+ ```
65
+
66
+ **Say:**
67
+
68
+ > Scan separates Loadout-managed skills from files I already had. Status keeps source
69
+ > and version ownership, and rollback restores the exact pre-install snapshot while
70
+ > preserving unrelated skills. I use the exact snapshot ID shown by the install, so
71
+ > there is no ambiguity. Complete uninstall is available too.
72
+
73
+ ### 1:12–1:42 — broad library, focused project
74
+
75
+ **Screen:** Use the already downloaded Maximum library from the acceptance run. Show
76
+ the first part of `library`, then run the two read-only commands.
77
+
78
+ ```bash
79
+ loadout library
80
+ loadout recommend --project . --agent codex
81
+ loadout optimize --project . --agents codex,claude-code --limit 30
82
+ ```
83
+
84
+ **Say:**
85
+
86
+ > Maximum does not dump thousands of skills into every prompt. It keeps the broad
87
+ > screened catalog disabled, detects this TypeScript CLI project, and proposes a
88
+ > focused active set for each agent. That is the core idea: discover broadly, activate
89
+ > narrowly, and keep every change reversible.
90
+
91
+ ### 1:42–2:05 — MCP, tools, and custom skills
92
+
93
+ **Screen:**
94
+
95
+ ```bash
96
+ loadout mcp-recipe --credential-free
97
+ loadout mcp-recipe playwright --agent codex
98
+ loadout tool graphify --agents codex,claude-code
99
+ loadout install --mode custom --package humanizer --agents codex
100
+ ```
101
+
102
+ **Say:**
103
+
104
+ > MCP servers and executable tools are never hidden inside a profile. Playwright is a
105
+ > separately previewed MCP recipe; Graphify is a pinned runtime tool; and a catalog
106
+ > skill such as Humanizer can be installed directly through Custom mode. Each path
107
+ > discloses permissions and credentials before approval.
108
+
109
+ ### 2:05–2:25 — today and tomorrow
110
+
111
+ **Screen:**
112
+
113
+ ```bash
114
+ loadout update
115
+ loadout discover --limit 5
116
+ ```
117
+
118
+ **Say:**
119
+
120
+ > Update checks managed pinned sources without silently changing them. Discovery
121
+ > watches a wider ecosystem and queues new projects for review, so something going
122
+ > viral can be noticed quickly without being trusted blindly.
123
+
124
+ ### 2:25–2:48 — Codex, GPT-5.6, and close
125
+
126
+ **Screen:** README section “Built with Codex and GPT-5.6”, then return to the hero.
127
+
128
+ **Say:**
129
+
130
+ > We used Codex and GPT-5.6 throughout the build: architecture, threat modelling,
131
+ > cross-platform implementation, repo-wide debugging, tests, and the real founder
132
+ > acceptance loop. Those tests caught rollback, project-scope, inventory, and update
133
+ > bugs on my actual Codex and Claude profiles. Loadout itself stays local and does not
134
+ > require an OpenAI API key. One command gives your AI agents a loadout you can
135
+ > understand, improve, and undo.
136
+
137
+ ## Final edit and upload
138
+
139
+ - Remove loading screens, typing pauses, repeated commands, notifications, and secrets.
140
+ - Keep terminal output readable at 1080p; do not use a synthetic dashboard or mock data.
141
+ - Add a small title card: **Loadout — Agent extensions, under control.**
142
+ - Export under three minutes and upload publicly to YouTube.
143
+ - Watch the uploaded video once, confirm audio and text are legible, then paste the
144
+ exact public URL into README and Devpost.
145
+
146
+ ## Submission checklist
147
+
148
+ - [ ] Public YouTube video is under three minutes and its URL opens signed out.
149
+ - [ ] Voiceover explains the product, Codex usage, and GPT-5.6 usage.
150
+ - [ ] `/feedback` was run in Codex and the session ID is in Devpost.
151
+ - [ ] Repository URL is accessible to Devpost and OpenAI.
152
+ - [ ] README has npm setup and the judge testing path.
153
+ - [ ] Every teammate has accepted the Devpost invitation.
154
+ - [ ] Category is **Developer Tools**.
155
+ - [ ] Submission is submitted, not left as a draft.
@@ -211,7 +211,7 @@ cleanup deliberately deletes Loadout's snapshots, so it is the last lifecycle te
211
211
  ## Troubleshooting and recovery
212
212
 
213
213
  - **`loadout` is not found after installation:** confirm `npm install --global
214
- loadout-ai@0.5.5` completed, run `hash -r`, and confirm npm's global binary
214
+ loadout-ai@0.5.7` completed, run `hash -r`, and confirm npm's global binary
215
215
  directory is on `PATH`. For a source checkout, run `npm run build` and `npm link`.
216
216
  - **A preview asks for `--approve-risk`:** read the reported scripts, domains,
217
217
  credentials, binaries, or instruction findings. If you accept that specific plan,
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loadout-ai",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "description": "Universal upgrade manager for AI coding agents",