docs/design/workspace-skills-read-model.md
GET /workspace/skills currently delegates to the ACP child. The child status
handler refreshes both the extension and skill caches before returning a
response. Web reconnects therefore turn a read-only status query into a full
extension scan and skill parse.
The fix is staged:
SkillManager
cache. A cold cache — or a config with no SkillManager at all — returns
initialized: false; it never scans or parses in response to a status
request. Explicit mutation and refresh commands remain the imperative
refresh paths.stat-only
validity check. Skills have a watcher; extensions do not, so a read verifies
that the extension directory entries, their manifests, the enablement file,
and the store's activation state are where the last refresh left them, and
refreshes the extension and skill caches only when they moved. This preserves
the pre-change behavior for extension install / enable / disable run outside
the daemon, at one readdir plus one stat per entry plus two, instead of a
directory scan and a full manifest and skill parse. Skipped in safe and bare
mode, which deliberately never populate the extension cache at all.SkillManager once before publishing session command updates.The child route remains available for older daemon parents. New child versions serve it from memory, so an old parent is safe even if it continues querying on every reconnect.
readdir the extensions directory and stat a
bounded set of paths — one per entry plus two — and refreshes only when that
set moved.Skill enablement is read from the child's in-memory LoadedSettings rather than
re-loaded per request. SettingsWatcher keeps the User and Workspace scopes
current, so the common paths — the daemon's own toggle, a /skills toggle in a
terminal, a hand edit — are covered. Two narrow cases are not: the System and
SystemDefaults scopes have no watcher, so a policy change to the locked-skill
list is not reflected until an explicit refresh; and an untrusted workspace does
not watch the Workspace scope at all. Both were previously self-healing because
every read reloaded settings from disk.
The cached read API is additive. Existing callers of listSkills() keep its
lazy-load behavior. Existing HTTP and ACP response shapes remain compatible;
refresh-result fields are additive.