stacklok / stacklok/mecatl

feat(skills): reload external skill inventory for an idle session

Open
#1,424 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Go
Stars
152
Forks
16
Avg merge
14h 48m
Merged PRs (30d)
536

Description

User outcome

An authorized caller can explicitly reload externally configured skills for one existing session without restarting the server or affecting other sessions.

V1 is a silent model-facing reload: source and dispatch state refresh, but the model continues to receive the skill inventory it was already advertised. This preserves the provider prompt-cache generation. The initial user-facing affordance is /reload-skills in mecatui, backed by a server-owned control operation.

This is intentionally useful but incomplete for discovery:

  • an already advertised skill whose body changed loads its refreshed body when invoked;
  • a newly added skill is callable only when its name is supplied explicitly (for example, by the user through /name), not through autonomous discovery from the stale model inventory;
  • a removed skill may remain advertised for the session and must return an honest unavailable/unknown result if invoked;
  • the TUI may refresh its user-facing palette/inventory after a successful reload, but that must not alter the model-facing tool definition in V1.

Current behavior

External skills are deployment/build-lifetime snapshots:

  • tool.SkillSource guarantees stable ListSkills output for the source lifetime and documents no watch/reload seam.
  • Local skillfs.FSSource snapshots skill metadata and SKILL.md bodies at construction; only an already-known skill's logical assets are disk-live.
  • internal/app resolves the external skill seam once into process-wide catalogAssets.
  • The Skill tool, skill-backed /<skill-name> commands, agent-definition skills: preload index, and skill inventory/listing derive from that seam.

Today the Skill tool description embeds the full name/description inventory. Rebuilding it with changed metadata alters an early provider tool-definition input. Anthropic documents that changing tool definitions invalidates the entire tools/system/messages prompt-cache hierarchy; OpenAI likewise includes tool definitions in its rendered cache prefix.

V1 contract: silent model-facing reload

Add an explicit session-scoped ReloadSessionSkills control operation, exposed by the mecatui /reload-skills builtin.

  • Caller supplies only the owned session ID; it cannot select directories, source URLs, workspace paths, or trust settings.
  • Reload is accepted only for an inactive, non-awaiting session. Reject a live or awaiting run; do not queue an implicit reload or mutate state mid-turn.
  • Re-resolve sources through the existing composition-owned skillResolveOptions / resolveSkillSeam path. This must preserve configured precedence and reapply the project-ingestion trust gate; do not duplicate source resolution in the server handler.
  • Install a complete replacement external skill source/catalog for the target session through the existing engine-replacement lifecycle. A default session may need promotion from the shared default engine to a private per-session engine.
  • Preserve the previous model-facing Skill tool specification, including its advertised names/descriptions, while routing Skill activation to the refreshed source/inventory. Do not alter the generic tool description, tools array, system prompt, or persisted conversation merely because reload occurred.
  • Rebuild user-initiated skill slash-command expansion and command-palette listing from the refreshed source. A user who knows a newly added name can invoke it; that does not imply the model discovers it unaided.
  • Rebuild the agent-definition skill preload index for newly constructed specialist-agent engines, while leaving any model-visible generic inventory unchanged.
  • Preserve non-skill session characteristics and catalog inputs: exact placement/profile, provider/model/mode, client-MCP attachment, global MCP, hooks, permissions, memory, and learning partitions.
  • On discovery or engine-build failure, retain the currently installed session catalog unchanged. Return bounded status/count metadata only; no paths, skill bodies, source configuration, or private placement metadata.
  • Reload is process-local and session-local in V1. It does not persist a separate external-skill generation; after server restart normal startup snapshot semantics apply.

Scope

  • internal/app: composition-owned session refresh factory/seam, using the existing skill source resolver and the single assembleCatalog registration path.
  • internal/adapter/server: caller authorization, run/awaiting/lease checks, engine replacement, and an additive authenticated RPC/HTTP control operation.
  • contracts/proto: additive control request/response if gRPC support is added; regenerate generated contracts.
  • cmd/mecatui/client and cmd/mecatui/ui: server collaborator, /reload-skills builtin, and user-facing palette/inventory refetch.
  • engine/adapter/skillfs: separate the Skill tool's advertised inventory from its refreshed activation inventory so V1 can preserve its prior ToolSpec byte-for-byte while serving refreshed bodies/known names.
  • User documentation: semantics, source/trust behavior, active-run rejection, silent-model-discovery limitation, and cache-preservation rationale.

Acceptance criteria

  • A reload in session A cannot change source/dispatch state, tool metadata, slash commands, or agent preloads in session B.
  • Active and awaiting sessions reject reload with a stable failed-precondition response; no engine/catalog is closed or swapped.
  • A failed reload leaves the old source/catalog usable.
  • The model-facing Skill tool specification is byte-identical before and after a V1 reload, preserving the existing provider cache generation.
  • An already-advertised skill with a changed body returns the refreshed body after reload.
  • A newly added skill can be activated by an explicit known name after reload but is absent from the model-facing inventory.
  • A removed yet previously advertised skill fails honestly on activation; it is never silently substituted.
  • User-facing palette and /<skill-name> expansion reflect the refreshed source after successful reload.
  • Project-tier skills remain absent unless the existing trust decision admits them; explicit/user tiers retain their current behavior and precedence.
  • Added, edited, removed, malformed, and name-shadowed external skills have deterministic results after reload.
  • Existing learned-skill partitions retain their caller/project isolation if learning is enabled.
  • Tests are offline; all normal engine/public API compatibility rules remain intact.

Deferred follow-on: model-visible, cache-aware inventory refresh

A later design may keep the generic Skill tool definition stable while delivering an updated skill name/description inventory through an append-only, late-positioned, trusted model-context notice. This should be treated as separate work, not smuggled into V1.

It requires a provider-neutral way to represent a mid-conversation harness/system reminder, provider-specific rendering and cache-breakpoint behavior, lifecycle/persistence semantics, and an atomic binding between the notice's advertised generation and the dispatchable source. It must not rewrite existing history, accumulate unbounded notices, or expose source paths/assets. This work may need extensions to the session and LLM-provider handling layers.

Non-goals

  • Filesystem watching or automatic reload.
  • Telling the model that a V1 reload occurred or updating its available-skill list.
  • Process-wide reload or mutating shared catalogAssets.
  • Reload during a live model/tool turn.
  • Reusing learned-skill publication as a filesystem reload mechanism.
  • Persisting reproducible external-skill generations across restart.
  • Exposing paths/assets as workspace roots or making skill assets executable.

Relevant code

  • engine/tool/skillsource.go — external source snapshot contract.
  • engine/adapter/skillfs/fssource.go and resolve.go — filesystem source snapshot, source locations, and precedence.
  • engine/adapter/skillfs/tool.go — current coupled advertised/activation inventory.
  • internal/app/build.go (skillResolveOptions, resolveSkillSeam, buildCommandExpander) — trust-gated composition and slash-command bridge.
  • internal/app/catalog.go (catalogAssets, assembleCatalog, registerSkillFamily) — shared assets and canonical registration path.
  • internal/adapter/server/service.go (engineAndEnvironmentFor, session engine replacement) — run-safe engine lifecycle.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with internal/app/build.go and catalog.go to trace skill resolution and canonical registration, then read engine/adapter/skillfs/tool.go and internal/adapter/server/service.go for inventory coupling and session engine replacement. Use the listed acceptance criteria as the completion check: inactive sessions reload independently, failed reloads preserve the old catalog, and the model-facing Skill ToolSpec remains byte-identical while refreshed activation and user commands work.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, backend, cli, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.