Friction: #482/#483 installed the embedded /query-corveil slash command into {devRoot}/.claude/commands/query-corveil.md via a Scaffolder pass at app launch (Scaffolder.swift:155 calls installCorveilSkill(...), invoked from AppDelegate.swift:418 initial-launch and :1087 workspace-switch). Changing the picker value in Settings (SettingsView.swift:603-609 writes config.defaults.binaries["corveil"]) doesn't fire a fresh Scaffolder pass, so the new path doesn't reach the installer until the user quits and relaunches Crow — or until they happen to switch workspaces and trip the alternate scaffold path.
The "Verify" button at SettingsView.swift:615 only runs --version. It doesn't re-install.
Result: user picks a path → Settings persists it → nothing else happens. User reasonably assumes it's installed, then discovers it isn't until they restart Crow. The fix is small.
Fix — hot-trigger the install on picker change
When config.defaults.binaries["corveil"] changes (path set, changed, or cleared), call Scaffolder.installCorveilSkill(newPath) once. Async, off the main thread (the existing Scaffolder.corveilInstallTimeout already bounds it; same Task wrapper SettingsView uses for --version at :699).
Three concrete places to wire:
-
Settings picker didSet (or the SwiftUI binding's set closure) at SettingsView.swift:603-609. After persisting the new value, dispatch installCorveilSkill against the new path. If the new value is empty (user cleared the field), call the installer with nil so it skips and clears any prior warning.
-
Reuse the existing warning surface. installCorveilSkill already returns a String? warning that's written to AppState.corveilSkillInstallWarning (per AppState.swift:237). Same plumbing applies here — surface success or the same banner that the launch-time pass uses.
-
Don't re-run the rest of Scaffolder. This is just the corveil install step; the full scaffold pass is unnecessary and would be wasteful. Extract installCorveilSkill to be callable independently if it isn't already (it appears private in Scaffolder.swift:230 — make it accessible to Settings, either via a public Scaffolder method or via a small published service).
Acceptance
- Initial pick: With
defaults.binaries.corveil unset and query-corveil.md not yet present, open Settings, set the picker to a valid corveil binary, save. Without restarting Crow, {devRoot}/.claude/commands/query-corveil.md exists and /query-corveil is invokable from any new Claude Code session in that devroot.
- Path change: With a working install, change the picker to point at a different corveil binary (e.g. a rebuilt version). Without restarting,
{devRoot}/.claude/commands/query-corveil.md reflects the new binary's embedded skill content (byte-compare against <newPath> skill show).
- Clear: Setting the picker to empty triggers no install attempt and clears any prior
corveilSkillInstallWarning. The existing query-corveil.md file is left in place — clearing the picker doesn't remove the skill (the user can do that manually if needed; not in scope here).
- Failure surfacing: Picking a broken path (non-existent / not executable) sets
corveilSkillInstallWarning to the same diagnostic the launch-time path produces, and the existing banner in the app surfaces it. No crash, no startup-loop, no broken file written.
- Rebuild rebuild loop: With a stable picker pointing at a locally-built corveil, running
go build ./cmd/corveil in the corveil repo and then clicking the Verify button (or any other trigger that re-evaluates) should not re-install (Verify is --version only — keep that contract). The user still gets a fresh install on the next launch, or could re-pick the same path to force one. (Optional follow-up: a "Reinstall skill" button next to Verify if this trips users; not in this ticket.)
Critical files
| Purpose |
Path |
| Picker binding (where to fire the install on change) |
Packages/CrowUI/Sources/CrowUI/SettingsView.swift:597-615 |
| Installer function |
Sources/Crow/App/Scaffolder.swift:230 (installCorveilSkill) — make accessible to Settings |
| Warning surface |
Packages/CrowCore/Sources/CrowCore/AppState.swift:237 (corveilSkillInstallWarning) |
| Existing async Task pattern to mirror |
Packages/CrowUI/Sources/CrowUI/SettingsView.swift:699 (the Verify Task wrapper) |
Out of scope
Related
🐦⬛ Created with Crow via Claude Code
Friction: #482/#483 installed the embedded
/query-corveilslash command into{devRoot}/.claude/commands/query-corveil.mdvia a Scaffolder pass at app launch (Scaffolder.swift:155callsinstallCorveilSkill(...), invoked fromAppDelegate.swift:418initial-launch and:1087workspace-switch). Changing the picker value in Settings (SettingsView.swift:603-609writesconfig.defaults.binaries["corveil"]) doesn't fire a fresh Scaffolder pass, so the new path doesn't reach the installer until the user quits and relaunches Crow — or until they happen to switch workspaces and trip the alternate scaffold path.The "Verify" button at
SettingsView.swift:615only runs--version. It doesn't re-install.Result: user picks a path → Settings persists it → nothing else happens. User reasonably assumes it's installed, then discovers it isn't until they restart Crow. The fix is small.
Fix — hot-trigger the install on picker change
When
config.defaults.binaries["corveil"]changes (path set, changed, or cleared), callScaffolder.installCorveilSkill(newPath)once. Async, off the main thread (the existingScaffolder.corveilInstallTimeoutalready bounds it; sameTaskwrapper SettingsView uses for--versionat:699).Three concrete places to wire:
Settings picker
didSet(or the SwiftUI binding'ssetclosure) atSettingsView.swift:603-609. After persisting the new value, dispatchinstallCorveilSkillagainst the new path. If the new value is empty (user cleared the field), call the installer withnilso it skips and clears any prior warning.Reuse the existing warning surface.
installCorveilSkillalready returns aString?warning that's written toAppState.corveilSkillInstallWarning(perAppState.swift:237). Same plumbing applies here — surface success or the same banner that the launch-time pass uses.Don't re-run the rest of Scaffolder. This is just the corveil install step; the full scaffold pass is unnecessary and would be wasteful. Extract
installCorveilSkillto be callable independently if it isn't already (it appears private inScaffolder.swift:230— make it accessible to Settings, either via a public Scaffolder method or via a small published service).Acceptance
defaults.binaries.corveilunset andquery-corveil.mdnot yet present, open Settings, set the picker to a valid corveil binary, save. Without restarting Crow,{devRoot}/.claude/commands/query-corveil.mdexists and/query-corveilis invokable from any new Claude Code session in that devroot.{devRoot}/.claude/commands/query-corveil.mdreflects the new binary's embedded skill content (byte-compare against<newPath> skill show).corveilSkillInstallWarning. The existingquery-corveil.mdfile is left in place — clearing the picker doesn't remove the skill (the user can do that manually if needed; not in scope here).corveilSkillInstallWarningto the same diagnostic the launch-time path produces, and the existing banner in the app surfaces it. No crash, no startup-loop, no broken file written.go build ./cmd/corveilin the corveil repo and then clicking the Verify button (or any other trigger that re-evaluates) should not re-install (Verify is--versiononly — keep that contract). The user still gets a fresh install on the next launch, or could re-pick the same path to force one. (Optional follow-up: a "Reinstall skill" button next to Verify if this trips users; not in this ticket.)Critical files
Packages/CrowUI/Sources/CrowUI/SettingsView.swift:597-615Sources/Crow/App/Scaffolder.swift:230(installCorveilSkill) — make accessible to SettingsPackages/CrowCore/Sources/CrowCore/AppState.swift:237(corveilSkillInstallWarning)Packages/CrowUI/Sources/CrowUI/SettingsView.swift:699(the Verify Task wrapper)Out of scope
defaults.binaries.*entries (codex, cursor). Those don't have a per-tool install step today — they only get the symlink + PATH treatment per Make defaults.binaries.* take precedence in spawned terminals (CROW-487) #489 / Make defaults.binaries.corveil take precedence in spawned terminals (symlink + PATH prepend) so /query-corveil and friends use the configured binary #487, and that resolves dynamically from PATH at agent-launch time, so no re-scaffold is needed.Related
corveil skill install. This ticket closes the "set once, must restart" gap that flow left.defaults.binaries.*precedence in spawned terminals via symlink + PATH prepend. Adjacent but separate axis (those resolve at agent-launch time; this ticket is about installing skill content at config-change time).AppDelegate.swift:418,:1087— the two existing launch-time call sites that invoke the scaffold pass. This ticket is the third trigger (config change), reusing the same install function.🐦⬛ Created with Crow via Claude Code