Why this matters
Every user turn, the engine appends a <recommended_plugins> fragment matched on conversation keywords. A session that merely talks about a topic gets the same plugin nag repeatedly, and the matcher cannot tell that a locally loaded skill already covers the domain. Users dismiss or ignore the prompt and it comes back next turn — it reads as spam, and each injection is wasted context.
Current behavior
crates/tui/src/core/engine.rs:3711 — user_content_blocks calls recommended_plugins_user_fragment(&text, …) on every user turn.
crates/tui/src/plugins/recommend.rs:232 — match_plugin_for_draft keyword/name matches score 700–900 while PROACTIVE_MIN_SCORE is 700, so a topical keyword always clears the proactive bar.
- Dismissals are honored (
settings.dismissed_plugin_suggestions), but there is no once-per-session cap and no loaded-skill awareness.
Repro (live, this session, 4 hits)
One real session, four different injections, each tracking the topic of the user's message rather than a capability gap:
- takeover/handoff talk → suggested
handoff (cw2:handoff) while the local cw-handoff skill was already loaded
- continuation mentioning research →
research (cw2:research)
- goal-continuation text →
remember (anthropic:remember)
- a pasted summary mentioning release →
release (cw2:release)
Desired behavior
- A plugin id is injected at most once per Engine lifetime (evaluate once, consume — the grokbuild pattern:
refs/grokbuild …/app_view.rs ssh_wrap_tip_evaluated one-shot tips; kimicode's capability catalog is pull-based with no proactive keyword injection).
- Suppress a suggestion when a loaded local skill already covers the plugin name/domain (skill
handoff loaded → never suggest plugin handoff).
- Keep honoring dismissals; keep the fragment append-only on the user turn (never the pinned system prefix).
Acceptance criteria
Related
Why this matters
Every user turn, the engine appends a
<recommended_plugins>fragment matched on conversation keywords. A session that merely talks about a topic gets the same plugin nag repeatedly, and the matcher cannot tell that a locally loaded skill already covers the domain. Users dismiss or ignore the prompt and it comes back next turn — it reads as spam, and each injection is wasted context.Current behavior
crates/tui/src/core/engine.rs:3711—user_content_blockscallsrecommended_plugins_user_fragment(&text, …)on every user turn.crates/tui/src/plugins/recommend.rs:232—match_plugin_for_draftkeyword/name matches score 700–900 whilePROACTIVE_MIN_SCOREis 700, so a topical keyword always clears the proactive bar.settings.dismissed_plugin_suggestions), but there is no once-per-session cap and no loaded-skill awareness.Repro (live, this session, 4 hits)
One real session, four different injections, each tracking the topic of the user's message rather than a capability gap:
handoff (cw2:handoff)while the localcw-handoffskill was already loadedresearch (cw2:research)remember (anthropic:remember)release (cw2:release)Desired behavior
refs/grokbuild …/app_view.rsssh_wrap_tip_evaluatedone-shot tips; kimicode's capability catalog is pull-based with no proactive keyword injection).handoffloaded → never suggest pluginhandoff).Acceptance criteria
user_content_blocksor the fragment fn with a session-state set)cargo test -p codewhale-tui --lib --lockedgreen for the touched modulesRelated
release; it does not, and the liveness filter says it could not #6272 (adjacent remedy-text accuracy in the same suggestion surface)